September 04, 2006
Walter Bright wrote:
> Ivan Senji wrote:
>> Maybe not the right time to mention it but: one of the most annoying error messages dmd produces is "is not an lvalue". An annoying message isn't doesn't make a good first impression, and it makes an even worse second or third impression.
>>
>> Example:
>>
>>   class A
>>   {
>>     int xx = 11;
>>     int opIndex(int pos){return xx;}
>>     int opIndexAssign(int what, int pos){return xx = what;}
>>
>>     int prop(){return xx;}
>>     int prop(int newxx){return xx = newxx;}
>>   }
>>
>>   auto a = new A;
>>
>>   void f(inout int x)
>>   {
>>     x ++;
>>   }
>>
>>   f(a[5]);    //((a).opIndex)(5) is not an lvalue
>>   f(a.prop);  //((a).prop)() is not an lvalue
>>
>> Maybe a[5] isn't strictly an lvalue because it's adress can't be taken but, it would make much sense for the compiler to translate those cases to (and shouldn't be that hard to do):
>>
>> auto x = a[5];
>>   f(x);
>> a[5] = x;
>>
>> auto y = a.prop;
>>   f(y);
>> a.prop = y;
>>
>> I don't want to sound lika a D-hater because of my recent (complaining) posts but just trying to show that although D is a fantastic language it is still a little too rough around the edges.
> 
> The compiler can translate those cases, but I feel that would be the wrong thing to do. If a function has inout for a parameter, it means that the function is expected to essentially return a value through the parameter. If the user calls a function with a parameter that cannot accept such a return value, it is most likely a mistake. If the compiler rewrites the code so it "works", then it's probably going to make finding the bug difficult.

Hmm, I'm going to have to look into it a little bit further. I understand the potential problems with the compiler converting this. But isn't also a change from a field to a property that breaks existing code also a problem (maybe even a bigger one)? This has happened to me more than once.

Inout means return a value through the param? I agree, but it is a limitation that it cannot be returned into property.

The compiler could always issue a nice warning message if read or write property is missing.

> 
> It's an error in C++ for the same reason (can't initialize a reference with a non-const).
September 04, 2006
Sean Kelly wrote:
> Don Clugston wrote:
>> Walter Bright wrote:
>>> Bruno Medeiros wrote:
>>>> Walter Bright wrote:
>>>>> Any compelling reason why not? I know that everyone (including me) wants more features, more improvements, etc., but nothing about calling it 1.0 will prevent that from happening.
>>
>> Provided that the future plans for new syntax don't involve breaking lots of existing code, then I would say yes. I'm not yet convinced that this is true for the future RAII syntax (but I'm not convinced that it isn't true, either).
> 
> Good point.  Personally, I'd like to get the new syntax now, even if stack allocation doesn't occur until later.

Me too. If we know that things in the future are going to break, we want to break them now if at all possible.

  I think this means
> potentially dropping 'auto' from class declarations (so "auto class C {}" would be illegal) and making duplicate storage classes illegal for declarations (so "auto auto x = new MyClass()" would be illegal).  Also:
> 
>     MyClass c = MyClass();
> 
> could convert to:
> 
>     MyClass c = new MyClass();
>     scope(exit) delete c;
> 
> and:
> 
>     char[] b = char[32];
> 
> could convert to:
> 
>     char[] b = new char[32];
>     scope(exit) delete b;
> 
> With the appropriate extensions for type inference as well. Alternately, alloca could be used for the allocations if that's possible.
> 
> 
> Sean
September 04, 2006
On Mon, 04 Sep 2006 10:42:19 -0700, Walter Bright wrote:

> Ivan Senji wrote:
>> Maybe not the right time to mention it but: one of the most annoying error messages dmd produces is "is not an lvalue". An annoying message isn't doesn't make a good first impression, and it makes an even worse second or third impression.
>> 
>> Example:
>> 
>>   class A
>>   {
>>     int xx = 11;
>>     int opIndex(int pos){return xx;}
>>     int opIndexAssign(int what, int pos){return xx = what;}
>> 
>>     int prop(){return xx;}
>>     int prop(int newxx){return xx = newxx;}
>>   }
>> 
>>   auto a = new A;
>> 
>>   void f(inout int x)
>>   {
>>     x ++;
>>   }
>> 
>>   f(a[5]);    //((a).opIndex)(5) is not an lvalue
>>   f(a.prop);  //((a).prop)() is not an lvalue
>> 
>> Maybe a[5] isn't strictly an lvalue because it's adress can't be taken but, it would make much sense for the compiler to translate those cases to (and shouldn't be that hard to do):
>> 
>> auto x = a[5];
>>   f(x);
>> a[5] = x;
>> 
>> auto y = a.prop;
>>   f(y);
>> a.prop = y;
>> 
>> I don't want to sound lika a D-hater because of my recent (complaining) posts but just trying to show that although D is a fantastic language it is still a little too rough around the edges.
> 
> The compiler can translate those cases, but I feel that would be the wrong thing to do. If a function has inout for a parameter, it means that the function is expected to essentially return a value through the parameter. If the user calls a function with a parameter that cannot accept such a return value, it is most likely a mistake. If the compiler rewrites the code so it "works", then it's probably going to make finding the bug difficult.
> 
> It's an error in C++ for the same reason (can't initialize a reference with a non-const).

You are right Walter. However, a[5] looks looks like an lvalue doesn't it? In fact, it could have been one until the class author changed it to a property.  I feel that Properties need to behave as if they were data members rather than methods when used as such. Thus ...

  f(a.prop);
and
  f(a.prop());

would look *and* behave differently but without surprising the coder.

And this also means that

  a.prop++

needs to work too. It is a great surprise to new comers that obvious things like this are not working as expected.

-- 
Derek Parnell
Melbourne, Australia
"Down with mediocrity!"
September 04, 2006
Derek Parnell wrote:
> On Mon, 04 Sep 2006 10:42:19 -0700, Walter Bright wrote:
> 
>> Ivan Senji wrote:
>>> Maybe not the right time to mention it but: one of the most annoying error messages dmd produces is "is not an lvalue". An annoying message isn't doesn't make a good first impression, and it makes an even worse second or third impression.
>>>
>>> Example:
>>>
>>>   class A
>>>   {
>>>     int xx = 11;
>>>     int opIndex(int pos){return xx;}
>>>     int opIndexAssign(int what, int pos){return xx = what;}
>>>
>>>     int prop(){return xx;}
>>>     int prop(int newxx){return xx = newxx;}
>>>   }
>>>
>>>   auto a = new A;
>>>
>>>   void f(inout int x)
>>>   {
>>>     x ++;
>>>   }
>>>
>>>   f(a[5]);    //((a).opIndex)(5) is not an lvalue
>>>   f(a.prop);  //((a).prop)() is not an lvalue
>>>
>>> Maybe a[5] isn't strictly an lvalue because it's adress can't be taken but, it would make much sense for the compiler to translate those cases to (and shouldn't be that hard to do):
>>>
>>> auto x = a[5];
>>>   f(x);
>>> a[5] = x;
>>>
>>> auto y = a.prop;
>>>   f(y);
>>> a.prop = y;
>>>
>>> I don't want to sound lika a D-hater because of my recent (complaining) posts but just trying to show that although D is a fantastic language it is still a little too rough around the edges.
>> The compiler can translate those cases, but I feel that would be the wrong thing to do. If a function has inout for a parameter, it means that the function is expected to essentially return a value through the parameter. If the user calls a function with a parameter that cannot accept such a return value, it is most likely a mistake. If the compiler rewrites the code so it "works", then it's probably going to make finding the bug difficult.
>>
>> It's an error in C++ for the same reason (can't initialize a reference with a non-const).
> 
> You are right Walter. However, a[5] looks looks like an lvalue doesn't it?
> In fact, it could have been one until the class author changed it to a
> property.  I feel that Properties need to behave as if they were data
> members rather than methods when used as such. Thus ...
> 
>   f(a.prop);
> and
>   f(a.prop());
> 
> would look *and* behave differently but without surprising the coder.
> 
> And this also means that 
> 
>   a.prop++
> 
> needs to work too. It is a great surprise to new comers that obvious things
> like this are not working as expected.
> 

And what about:

a.prop.y = 7;

Where prop is/returns a struct { int x,y; } ?

-- 
Oskar
September 04, 2006
Walter Bright wrote:
...
> 
> I'd much rather work on the features the people who have *already* switched to D need to do outrageously cool things.
> ...

The only thing I can think of that D is missing is run-time specification of type, and that doesn't seem as if it would easily fit in with the rest of D.  Possibly for D 2.0 *or* 3.0.

What I would really *LIKE* is an interim way of connecting easily to Python or Ruby (either one!).  Something like what Pyrex does for Python.  (Yes, I know that's also an absurd request...but that might be handleable with a library.  Perhaps.)

What's needed now, as we approach RC1, is a DEPENDABLY STABLE language.  That, and a big push on libraries.  When I decide which language to use, libraries are generally the deciding point.  (Not always...just recently is was the lack of run-time typing, but that's rarely an issue, and libraries are more significant.)
September 04, 2006
Oskar Linde wrote:
> Derek Parnell wrote:
> 
>> On Mon, 04 Sep 2006 10:42:19 -0700, Walter Bright wrote:
>>
>>> Ivan Senji wrote:
>>>
>>>> Maybe not the right time to mention it but: one of the most annoying error messages dmd produces is "is not an lvalue". An annoying message isn't doesn't make a good first impression, and it makes an even worse second or third impression.
>>>>
>>>> Example:
>>>>
>>>>   class A
>>>>   {
>>>>     int xx = 11;
>>>>     int opIndex(int pos){return xx;}
>>>>     int opIndexAssign(int what, int pos){return xx = what;}
>>>>
>>>>     int prop(){return xx;}
>>>>     int prop(int newxx){return xx = newxx;}
>>>>   }
>>>>
>>>>   auto a = new A;
>>>>
>>>>   void f(inout int x)
>>>>   {
>>>>     x ++;
>>>>   }
>>>>
>>>>   f(a[5]);    //((a).opIndex)(5) is not an lvalue
>>>>   f(a.prop);  //((a).prop)() is not an lvalue
>>>>
>>>> Maybe a[5] isn't strictly an lvalue because it's adress can't be taken but, it would make much sense for the compiler to translate those cases to (and shouldn't be that hard to do):
>>>>
>>>> auto x = a[5];
>>>>   f(x);
>>>> a[5] = x;
>>>>
>>>> auto y = a.prop;
>>>>   f(y);
>>>> a.prop = y;
>>>>
>>>> I don't want to sound lika a D-hater because of my recent (complaining) posts but just trying to show that although D is a fantastic language it is still a little too rough around the edges.
>>>
>>> The compiler can translate those cases, but I feel that would be the wrong thing to do. If a function has inout for a parameter, it means that the function is expected to essentially return a value through the parameter. If the user calls a function with a parameter that cannot accept such a return value, it is most likely a mistake. If the compiler rewrites the code so it "works", then it's probably going to make finding the bug difficult.
>>>
>>> It's an error in C++ for the same reason (can't initialize a reference with a non-const).
>>
>>
>> You are right Walter. However, a[5] looks looks like an lvalue doesn't it?
>> In fact, it could have been one until the class author changed it to a
>> property.  I feel that Properties need to behave as if they were data
>> members rather than methods when used as such. Thus ...
>>
>>   f(a.prop);
>> and
>>   f(a.prop());
>>
>> would look *and* behave differently but without surprising the coder.
>>
>> And this also means that
>>   a.prop++
>>
>> needs to work too. It is a great surprise to new comers that obvious things
>> like this are not working as expected.
>>
> 
> And what about:
> 
> a.prop.y = 7;
> 
> Where prop is/returns a struct { int x,y; } ?
> 

I'm not a fan of the current property syntax either.  I'd be very happy to see Walter implement get/set syntax, or some such.  I just can't say this is a 1.0 issue though, unless it's going to be tough to rewrite code when it's changed.

Are there plans to change this in the future?
September 04, 2006
Derek Parnell wrote:
>> It's an error in C++ for the same reason (can't initialize a reference with a non-const).
> 
> You are right Walter. However, a[5] looks looks like an lvalue doesn't it?
> In fact, it could have been one until the class author changed it to a
> property.  I feel that Properties need to behave as if they were data
> members rather than methods when used as such. Thus ...
> 
>   f(a.prop);
> and
>   f(a.prop());
> 
> would look *and* behave differently but without surprising the coder.
> 
> And this also means that 
> 
>   a.prop++
> 
> needs to work too. It is a great surprise to new comers that obvious things
> like this are not working as expected.

Whether it's consistent or not depends on how you think about it - what your mental model is of it. I'd rather have the odd cases produce error messages rather than have the compiler paper over what is likely a programmer oversight.
September 04, 2006
Walter Bright wrote:
> Derek Parnell wrote:
>>> It's an error in C++ for the same reason (can't initialize a reference with a non-const).
>>
>> You are right Walter. However, a[5] looks looks like an lvalue doesn't it?
>> In fact, it could have been one until the class author changed it to a
>> property.  I feel that Properties need to behave as if they were data
>> members rather than methods when used as such. Thus ...
>>
>>   f(a.prop);
>> and
>>   f(a.prop());
>>
>> would look *and* behave differently but without surprising the coder.
>>
>> And this also means that
>>   a.prop++
>>
>> needs to work too. It is a great surprise to new comers that obvious things
>> like this are not working as expected.
> 
> Whether it's consistent or not depends on how you think about it - what your mental model is of it. I'd rather have the odd cases produce error messages rather than have the compiler paper over what is likely a programmer oversight.

Hmm, inconsistent is: changing a field to a property -> some code doesn't need to change, some code needs to change.

It seems that your mental model is that properties and the result of opIndex/opIndexAssign behaving like normal lvalues is the odd case?
Well in my mental model them behaving like lvalues is a normal case, and the current behavior is a wtf.

Actually I would like to know what this sentence of yours means:
"If the user calls a function with a parameter that cannot accept such a return value, it is most likely a mistake."

Does it mean if a property is passed that doesn't have a setter method? I would expect that to be reported at compile time as a nice "cannot pass read-only property as lvalue".

Is there an example where replacing

f(a.prop);

with

auto x=a.prop; f(x); a.prop=x;

would be a bad thing to do, and could result in unexpected code, or hard to catch bugs.
Sure some aspects of this behavior should be well documented to avoid confusion (like the fact that the value is updated on function exit) but it is the same with most other feature.

To make myself clear: D can do without this feature but without it a simple:

write f(a.prop) -> compile&run happily

is replaced with

write f(a.prop) -> compile -> goto line with error -> figure out the error and how to fix it (might be hard the first time) ->
select "f(a.prop)" -> Ctrl-X -> write auto x=a.prop; f(x); a.prop=x; ->
compile&run (but less happily now)
September 04, 2006
Ivan Senji wrote:
> Is there an example where replacing
> 
> f(a.prop);
> 
> with
> 
> auto x=a.prop; f(x); a.prop=x;
> 
> would be a bad thing to do, and could result in unexpected code, or hard to catch bugs.
> Sure some aspects of this behavior should be well documented to avoid confusion (like the fact that the value is updated on function exit) but it is the same with most other feature.
> 
> To make myself clear: D can do without this feature but without it a simple:
> 
> write f(a.prop) -> compile&run happily
> 
> is replaced with
> 
> write f(a.prop) -> compile -> goto line with error -> figure out the error and how to fix it (might be hard the first time) ->
> select "f(a.prop)" -> Ctrl-X -> write auto x=a.prop; f(x); a.prop=x; ->
> compile&run (but less happily now)

I'd ask "why is f(x) returning a value in x?" That would normally be an essential part of the behavior of the function, so:
	f(3)
should return an error, shouldn't it? If modifying its argument is an essential behavior of the function, and the argument is not modifiable, probably the programmer made a mistake and the compiler should not paper it over. And the same for every other argument that isn't an lvalue (and so cannot be set).

If you find yourself writing:

   auto x=a.prop; f(x); a.prop=x;

I would seriously question what is going on with f(). It's a big flag that something is wrong either with f() or with the usage of f(). I would not want the compiler papering it over.
September 04, 2006
On Mon, 04 Sep 2006 15:15:15 -0700, Walter Bright wrote:

> Derek Parnell wrote:
>>> It's an error in C++ for the same reason (can't initialize a reference with a non-const).
>> 
>> You are right Walter. However, a[5] looks looks like an lvalue doesn't it? In fact, it could have been one until the class author changed it to a property.  I feel that Properties need to behave as if they were data members rather than methods when used as such. Thus ...
>> 
>>   f(a.prop);
>> and
>>   f(a.prop());
>> 
>> would look *and* behave differently but without surprising the coder.
>> 
>> And this also means that
>> 
>>   a.prop++
>> 
>> needs to work too. It is a great surprise to new comers that obvious things like this are not working as expected.
> 
> Whether it's consistent or not depends on how you think about it - what your mental model is of it. I'd rather have the odd cases produce error messages rather than have the compiler paper over what is likely a programmer oversight.

What 'odd case'?

What 'programmer oversight'?

The coder writes

  a.prop++;

because the 'prop' is a data item in the object that she wants to increment. It is irrelevant to the coder whether or not the class author decided to implement this data item as a property or data member. From the perspective of the user of the class, 'prop' represents some data in the object. The implementation details are not a concern for the user of the class.

-- 
Derek Parnell
Melbourne, Australia
"Down with mediocrity!"