August 08, 2005
In article <dd89n6$2qd$1@digitaldaemon.com>, Manfred Nowak says...
>
>Sean Kelly <sean@f4.ca> wrote:
>
>[...]
>>>But according to the specs none of these can succesfully be implemented in D.
>> 
>> Why not?
>[...]
>
>Because the specs dont say what you get if you take the address of a formal inout parameter. This can be the address of the actual parameter as it is currently implemented in the reference compiler, but this is not guaranteed.
>
>The same holds for the values of the formal inout parameters.

Then this should be changed.  The properties of inout parameters should be well-defined.


Seam


August 08, 2005
In article <dd8a19$321$1@digitaldaemon.com>, Burton Radons says...
>
>llothar wrote:
>>>The problem with this function is indeed, that the outcome of giving the same variable to it, is undefined by design.
>> 
>> Don't know what you are talking about.
>> 
>> Program statements are executed in serial order. So it is well defined order. This design is the same as in all languages that use out or inout parameter.
>
>Now this was not part of the topic, but that's not true, and the current design is flawed enough that I think it should be reexamined.
>
>The other way to implement inout/out arguments is to read them on the function call, then write them after the call returns.  This is how any language with potential latency in message sends works (like CORBA), and it allows properties and opIndex to be used with inout parameters.  This lack of orthogonality is a problem.

This is great for CORBA, but I'm not sure I would like it within D.  I would much rather have a new attribute to specify this sort of behavior if in-language distributed programming were supported.

>The two are too different to interoperate.  If a current D function throws, any changes to an inout are stored; with a CORBA function they'd be scratched (this is the mechanically more useful option).  Then there's the fact that it removes pointer aliasing, which can be useful in some situations.

Agreed.  And I grant that the CORBA model is nice in some respects--it allows for some degree of automatic exception safety--but it's not worthwhile in a systems programming language.  I would much rather have a valid address for passed parameters, etc.


Sean


August 08, 2005
Manfred Nowak wrote:

> Sean Kelly <sean@f4.ca> wrote:
> 
> [...]
> 
>>>But according to the specs none of these can succesfully be implemented in D.
>>
>>Why not?
> 
> [...]
> 
> Because the specs dont say what you get if you take the address of a formal inout parameter. This can be the address of the actual parameter as it is currently implemented in the reference compiler, but this is not guaranteed.

Quit digging this hole.  You're wrong.  DMD IS the specification except in cases of direct contradiction.  This issue has come up before and that's how inout/out properties are defined because any other definition changes their semantics hugely, as you know.  Having the reference implementation partially define the specification is the nature of a beta language (and Walter being a lazy bastard).

You know, you could've just asked, "Hey what does this do, and is that standard?" instead of making a complete ass out of yourself.
August 08, 2005
Sean Kelly wrote:

> In article <dd8a19$321$1@digitaldaemon.com>, Burton Radons says...
> 
>>llothar wrote:
>>
>>>>The problem with this function is indeed, that the outcome of giving the same variable to it, is undefined by design.
>>>
>>>Don't know what you are talking about. 
>>>
>>>Program statements are executed in serial order. So it is well defined order.
>>>This design is the same as in all languages that use out or inout parameter.
>>
>>Now this was not part of the topic, but that's not true, and the current design is flawed enough that I think it should be reexamined.
>>
>>The other way to implement inout/out arguments is to read them on the function call, then write them after the call returns.  This is how any language with potential latency in message sends works (like CORBA), and it allows properties and opIndex to be used with inout parameters.  This lack of orthogonality is a problem.
> 
> 
> This is great for CORBA, but I'm not sure I would like it within D.  I would
> much rather have a new attribute to specify this sort of behavior if in-language
> distributed programming were supported.

But those ARE the keywords for that sort of behaviour.  D stole them from IDL, the language for defining CORBA interfaces.  Get your own damned keywords.  ;)

>>The two are too different to interoperate.  If a current D function throws, any changes to an inout are stored; with a CORBA function they'd be scratched (this is the mechanically more useful option).  Then there's the fact that it removes pointer aliasing, which can be useful in some situations.
> 
> 
> Agreed.  And I grant that the CORBA model is nice in some respects--it allows
> for some degree of automatic exception safety--but it's not worthwhile in a
> systems programming language.  I would much rather have a valid address for
> passed parameters, etc.

When that is the actual intention, you have pointers or maybe references if non-null addresses are vital.  If you want a function to have multiple returns, you have inout/out.

I don't think the valid address problem's as notable in D as it was in C++.  I mean, there's no way to ensure that you're passed a valid object reference, right?  It's certainly a big problem when it happens, but I haven't seen anyone ask for a non-null object qualifier.  Just stuff in an assert and move on to bigger problems.
August 08, 2005
Burton Radons <burton-radons@smocky.com> wrote:

[ some remarks about some people ]

I really like developers getting personal and through my hole business life I could not resist mentioning them to my boss with the emphasis that these are really nice people.

What I never understood in total was, that these people usually resignated to the next possible date.

So, if you want me that I praise your skills to the quality assurer of your company send me a private mail.

Meanwhile simply explain how you would solve the task that your implementation should forbid any call with identical actual parameters.

Thanks in advance.

-manfred

August 08, 2005
In article <dd8cu4$6ac$1@digitaldaemon.com>, Burton Radons says...
>
>Sean Kelly wrote:
>> 
>> Agreed.  And I grant that the CORBA model is nice in some respects--it allows for some degree of automatic exception safety--but it's not worthwhile in a systems programming language.  I would much rather have a valid address for passed parameters, etc.
>
>When that is the actual intention, you have pointers or maybe references if non-null addresses are vital.  If you want a function to have multiple returns, you have inout/out.

But inout *is* the D reference type :)

>I don't think the valid address problem's as notable in D as it was in C++.  I mean, there's no way to ensure that you're passed a valid object reference, right?  It's certainly a big problem when it happens, but I haven't seen anyone ask for a non-null object qualifier.  Just stuff in an assert and move on to bigger problems.

Personally, I vastly prefer value semantics to reference semantics--if I want references, I can always use pointers.  But that's another issue ;)  Perhaps 'is' could be extended to support this?  It's nice to have some way to determine if two parameters refer to the same thing.


Sean


August 08, 2005
AJG wrote:
>Regan Heath:
>>AJG:
>>
>>># int i = 0;
>>># void f( inout int i, inout int j ) { i = 1; j = 2; }
>>># f(i, i);
>>># // Here i is 2.
>>>
>>>The results are quite predictable, IMHO. I don't think there is anything  wrong with the language. How could this result be any different?
>>
Agreed

>>Is it not possible that an optimisiton compiler might re-order these  statements?
> 
> 
> Why on earth would it do that? You specifically told it the order you wanted
> them in. Such an "optimization" is erroneous. That's more like a
> transmogrification.
> 
Right, it can change it only if it can prove that that doesn't change the result. If i and j are local variables, it can prove this and reorder. If they are passed-in references, possibly to the same place, it clearly can't and won't. In general, if it wants to put a *test* in there to see if things overlap before doing some weird optimized thing, it can do that too (I think gcc4 will do that in vectorized code under some circumstances).

> 
> There are languages that specialize in writing easily parallelisable code (via
> syntax). D, coming roughly from normal C/C++, is not one of them. An extended
> version of C, called Cilk, does just that:
> 
> http://supertech.lcs.mit.edu/cilk/
> 
Thanks for the link - that looks really cool. It is becoming more and more clear to me that C's biggest weakness (for certain purposes, anyhow) is that, because it lets you do so much, without being explicit about what you really *intend*, the compiler really can't infer too much  about what you're specifically asking for; much of what your code asks for is not actually important. In the example, if you know that i and j will never refer to the same thing, (and there's no thread issues) then the order doesn't matter. But you have to write one before the other, and the C (or D) compiler will have to do them in that order.

So a lot of optimizations which you'd like to happen become unsafe and don't get done. Contrast to fortran: there are very few ways to manipulate a fortran array. This means coding tends to be long and tedious, but the compiler can infer what you are doing more easily.
> 
>>Is there any guarantee that the operations are carried out in the order  they have been typed? (if so, what is the point of the volatile block  statement?)
>>http://www.digitalmars.com/d/statement.html#volatile
> 
> 
> The guarantee (real or simulated) of order of execution is the very foundation
> of logical programming. If you couldn't rely on your statements being executed
> in the order you intended, then there is utter chaos.
>
Well put; but if you don't mind my saying, I think you glossed over the key issue a bit. 'real or simulated' is the key thing. Statements aren't always executed in the order you wrote them, but the results must be indistinguishable.

For instance if the example were:
void f( inout int i, inout int j, int k, int m )
{
    i = 22 + k*m - (k<<3);
    j = (k*m & 0x3FF)- (k^1);
}
... then the evaluation of the two expressions could of course be overlapped and interleaved, and k*m done once only, etc, but the write to i still needs to take place before the write to j. So they're not really being executed as you wrote them, but the results are the same.
> 
> Btw, that's why the NON-guarantee of order of execution in parameter calls (in
> C) is such a hotly debated issue. It is one exception to the rule. It's a
> mistake, IMO, that should be fixed.
>
It's one of those things, I haven't been bothered by it, any more than that the order of calls in f(x) + g(x) is undefined. The cost (in terms of code efficiency) of breaking up your expressions to eliminate problems with side-effects has basically gone to zero. I.e.  consider

      func(2*i,i++,f2(i));	/* not predictable, some wish it were */
vs.
      int f2res = f2(i+1)
      func(2*i, i, f2res );	/*assuming this is what you wanted :-)*/
      i++;

The second one is predictable, won't warp your brain, and should not be any less efficient with a modern compiler (as opposed to a 20-year C compiler, where it could be somewhat slower).

An expression is really just a flat description of a tree, I've never seen any reason why the different parts of the tree should be evaluated in any order (except as specified for || etc, of course), especially when the compiler can make better code by doing it in some particular order. Again, the more implicit control you give to the programmer, the more you are tying the compiler's hands in all the many cases where that control isn't actually needed.

Having said that - If C were going to be designed again - we could say, "Hey, if the compiler wants to evaluate function parms in some other order, then it can darn well prove first that it makes no difference relative to the language-specified order, and if it can't prove that, it can't reorder". This should still leave a lot of code reorderable.
  The state of compiler technology when C was designed was such that this would be an unreasonable limitation, equivalent to banning reordering. Even now, I'm guessing there would be a lot of cases where a compiler would need to generate extra code to evaluate them in order, even when it actually makes no difference, because it can't prove that.

And, unfortunately, if K&R had been forced to define an order, I suspect they would have gone with right-to-left (stack-push order) which is probably why they didn't. On some machines (especially older ones) there could be a serious penalty for left-to-right evaluation.

> 
>>In other words, is it possible for i to be 1 or 2 depending on what the  optimising compiler decides to do and/or the enviroment the code is  running in.
> 
> 
> Optimization should not alter the behaviour (intrinsic order) of such code,
> otherwise it is erroneous. I do not recall seeing anywhere "variable references
> may not refer to the same thing" but please do correct me if I'm wrong.
> 
Right.
As I see it, the solution is this: if you write a function where two or more reference parameters could refer to the same thing, and at least one of them is non-const, you should make an explicit note to potential users of the function as to whether that's allowed, and what the results are. Sometimes it's quite reasonable to pass the same thing in twice, and, by careful ordering of the writes (& reads) you can arrange to get the expected result. If you intend to *call* such a function with overlapped operands, and the author has *not* made such a note, then you're on your own... Even if the behaviour happens to be what you want, there's no contract that it won't change.

Example (in c):
- Greg
August 08, 2005
Georg Wrede wrote:

>>
>> hmmm, from the other posts I gather there is a small problem with this kind of code:
>> #int i = 5;
>> #f(i,i);
>> ^
>> such calls should be illegal; that is: no variable can be passed as an "out" parameter more than once.
>>
>> Is that -by any chance- what you are trying to hint to?
> 
> 
> Gee, this really ought to get into the language spec!

What about (a) when it's useful;
(b)when it's happening but the compiler can't tell, as in

int [100] ar;
int p;

void g(inout int ii, int j )
{
   f(ii,ar[j])
}

void glop(int k)
{
   g( ar[p], k )
}

when you call glop(20) and p == 20, you are calling f(ar[20],ar[20]).
You can't expect the  compiler to detect this. What exactly are you proposing to ban?

This comes under the heading of "Doctor, it hurts when I do this".

I once used a language called Euclid which managed to ban this sort of thing by making a huge number of useful things illegal. You essentially couldn't have more than one reference to any aggregate object (e.g array) around unless they were all read-only. To allow this to be enforced, the language's 'pointers' all had to be declared as tied to specific aggregate variables. So you couldn't shoot yourself in the foot, because your hands were tied behind your back and your feet were locked in a safe. The road to Euclid, was, indeed, paved with excellent intentions.

- Greg

August 09, 2005
Greg Smith <greg@siliconoptix.com> wrote:

[ well thought arguments]

Applause.

-manfred

August 09, 2005
Greg Smith wrote:
> Georg Wrede wrote:
> 
>>>
>>> hmmm, from the other posts I gather there is a small problem with this kind of code:
>>> #int i = 5;
>>> #f(i,i);
>>> ^
>>> such calls should be illegal; that is: no variable can be passed as an "out" parameter more than once.
>>>
>>> Is that -by any chance- what you are trying to hint to?
>>
>>
>>
>> Gee, this really ought to get into the language spec!
> 
> 
> What about (a) when it's useful;
> (b)when it's happening but the compiler can't tell, as in
> 
> int [100] ar;
> int p;
> 
> void g(inout int ii, int j )
> {
>    f(ii,ar[j])
> }
> 
> void glop(int k)
> {
>    g( ar[p], k )
> }
> 
> when you call glop(20) and p == 20, you are calling f(ar[20],ar[20]).
> You can't expect the  compiler to detect this. What exactly are you proposing to ban?

True.

I wasn't actually propsing anything, I was just wondering whether or not that was the intent of the OP.

Maybe a better idea would be to assert that passed parameters don't overlap in that particular function.

void f( inout int i, inout int j )
in
{
    assert( !std.overlap(i,j) ); //a standard function, or something like that
}
body
{
    ....
}


> 
> This comes under the heading of "Doctor, it hurts when I do this".
> 
> I once used a language called Euclid which managed to ban this sort of thing by making a huge number of useful things illegal. You essentially couldn't have more than one reference to any aggregate object (e.g array) around unless they were all read-only. To allow this to be enforced, the language's 'pointers' all had to be declared as tied to specific aggregate variables. So you couldn't shoot yourself in the foot, because your hands were tied behind your back and your feet were locked in a safe. The road to Euclid, was, indeed, paved with excellent intentions.
> 
> - Greg
>