Thread overview | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 11, 2013 More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Consider this code: --- int[int] x; int k = x[2] + 5; // Error, range violation. Makes sense. x[2] = x[2] + 5; // But this works!!! --- That is, x[2] doesn't exist, *unless you are about to assign to it*. What happens is: 1. lvalue index (creates x[2], sets it to int.init) 2. rvalue index (returns x[2], which is now 0) 3. lvalue index assign (sets x[2] = 5) In reality, step 1 returns a pointer to the newly created element. How could this be implemented as a library type? The superficially similar case, x[2] += 5; can be implemented with opIndexOpAssign. But I don't know how to do this one. Note that elements are not always magically created when an lvalue is required. AFAIK it only happens in assignment. For example this code gives a runtime error: --- void foo(ref int g) { ++g; } int[int] x; foo( x[2] ); // range error, x[2] doesn't exist yet --- |
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | On Friday, January 11, 2013 08:53:44 Don wrote:
> Consider this code:
> ---
> int[int] x;
>
> int k = x[2] + 5; // Error, range violation. Makes sense.
>
> x[2] = x[2] + 5; // But this works!!!
> ---
>
> That is, x[2] doesn't exist, *unless you are about to assign to it*.
>
> What happens is:
> 1. lvalue index (creates x[2], sets it to int.init)
> 2. rvalue index (returns x[2], which is now 0)
> 3. lvalue index assign (sets x[2] = 5)
>
> In reality, step 1 returns a pointer to the newly created element.
>
> How could this be implemented as a library type?
> The superficially similar case, x[2] += 5; can be implemented
> with opIndexOpAssign. But I don't know how to do this one.
>
> Note that elements are not always magically created when an lvalue is required. AFAIK it only happens in assignment. For example this code gives a runtime error:
> ---
> void foo(ref int g) { ++g; }
>
> int[int] x;
> foo( x[2] ); // range error, x[2] doesn't exist yet
> ---
I would argue that the fact that
x[2] = x[2] + 5;
works is a bug. Given some of the weirdness that happens with assigning to AA elements, it doesn't entirely surprise me. For instance,
x[2] = funcThatThrows();
results in x[2] holding the init value of x's element type. But I think that it's indicative of problems with the current AA implementation which need to be fixed and not something that we should be trying to emulate with library types.
- Jonathan M Davis
|
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Friday, 11 January 2013 at 08:26:54 UTC, Jonathan M Davis wrote:
> On Friday, January 11, 2013 08:53:44 Don wrote:
>> Consider this code:
>> ---
>> int[int] x;
>>
>> int k = x[2] + 5; // Error, range violation. Makes sense.
>>
>> x[2] = x[2] + 5; // But this works!!!
>> ---
>>
>> That is, x[2] doesn't exist, *unless you are about to assign to
>> it*.
>>
>> What happens is:
>> 1. lvalue index (creates x[2], sets it to int.init)
>> 2. rvalue index (returns x[2], which is now 0)
>> 3. lvalue index assign (sets x[2] = 5)
>>
>> In reality, step 1 returns a pointer to the newly created element.
>>
>> How could this be implemented as a library type?
>> The superficially similar case, x[2] += 5; can be implemented
>> with opIndexOpAssign. But I don't know how to do this one.
>>
>> Note that elements are not always magically created when an
>> lvalue is required. AFAIK it only happens in assignment. For
>> example this code gives a runtime error:
>> ---
>> void foo(ref int g) { ++g; }
>>
>> int[int] x;
>> foo( x[2] ); // range error, x[2] doesn't exist yet
>> ---
>
> I would argue that the fact that
>
> x[2] = x[2] + 5;
>
> works is a bug.
I completely agree. Doesn't the spec say that relying on
the order of assignment evaluation is undefined?
|
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | Don wrote: > Consider this code: > --- > int[int] x; > > int k = x[2] + 5; // Error, range violation. Makes sense. > > x[2] = x[2] + 5; // But this works!!! > --- I think the last statement is illegal. Because from http://dlang.org/expression.html I extract: The evaluation order of = is implementation defined and it is illegal to depend on it. The compiler should catch these but it cannot in all cases. If the evaluation order was fixed i.e. right-to-left in this case, the code would throw. It also happens that the evaluation may change depending on the optimization flags. So I believe it's an issue of evaluation order. Jens |
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Friday, 11 January 2013 at 08:26:54 UTC, Jonathan M Davis wrote: > On Friday, January 11, 2013 08:53:44 Don wrote: >> Consider this code: >> --- >> int[int] x; >> >> int k = x[2] + 5; // Error, range violation. Makes sense. >> >> x[2] = x[2] + 5; // But this works!!! >> --- >> >> That is, x[2] doesn't exist, *unless you are about to assign to >> it*. >> How could this be implemented as a library type? > I would argue that the fact that > > x[2] = x[2] + 5; > > works is a bug. Given some of the weirdness that happens with assigning to AA > elements, it doesn't entirely surprise me. For instance, > > x[2] = funcThatThrows(); > > results in x[2] holding the init value of x's element type. But I think that > it's indicative of problems with the current AA implementation which need to > be fixed and not something that we should be trying to emulate with library > types. That's my feeling too. I think that if we want to implement AAs as a library type, we first need to eliminate all of the semantics would be impossible to implement in a library. Specificially, I think we need to disallow semantics which are inconsistent with: struct AA { AAImpl impl; ref Value opIndex(Key key); Value opIndexAssign(Value value, Key key); Value opIndexOpAssign(string op)(Value value, Key key); } where the last two create the entry if it doesn't already exist. Those last two should also create a blank AA if it doesn't already exist. Personally I'd be much happier if instead, the blank AA was created at construction, so that AAs would be pure reference types, but at least the semantics are implementable. |
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | See also: http://d.puremagic.com/issues/show_bug.cgi?id=3825 Bye, bearophile |
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | On Friday, January 11, 2013 10:03:54 Don wrote:
> That's my feeling too. I think that if we want to implement AAs as a library type, we first need to eliminate all of the semantics would be impossible to implement in a library.
Well, the AAs are _already_ a library type. That's a large part of why they have so many bugs. The transition to a library type was badly done, and we sorely need a new implementation. Also, because the compiler is generating hooks that druntime plugs into, the built-in AAs aren't restricted to quite the same semantics that a user-defined AA type would be, even though the AAs are implemented in druntime instead of the compiler.
So, AFAIK, we don't really have a problem with the built-in AAs doing stuff that a library type can't do (that's not even possible at this point, because they're implemented with a library type). Rather, what we need is a new, properly templated solution. But that's a lot of work, and I believe that the last person who attempted it gave up on it beacuse of all the problems that he was running into.
- Jonathan M Davis
|
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | "Don" <don@nospam.com> wrote in message news:imqicbgjotdtzfgwdeor@forum.dlang.org... > Consider this code: > --- > int[int] x; > > int k = x[2] + 5; // Error, range violation. Makes sense. > > x[2] = x[2] + 5; // But this works!!! > --- > Definitely a bug. |
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bernard Helyer | Shouldn't the rhs be evaluated before the lhs? Why would it be undefined/unspecified/etc.? |
January 11, 2013 Re: More magical AA semantics | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bernard Helyer | On Friday, 11 January 2013 at 08:55:55 UTC, Bernard Helyer wrote:
> I completely agree. Doesn't the spec say that relying on
> the order of assignment evaluation is undefined?
After a long discussion with Andrei, it seems that it is left to right.
|
Copyright © 1999-2021 by the D Language Foundation