February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | Starting with magic initialisation then...
Is it vital that e[nonexistentKey] throw a RangeError, or could it just always return the type's default value if the key is absent?
If you change that, then you can make assignment evaluate the RHS fully before even creating the LHS entry, and you won't in the process break the common case where people want to go
count[key]++;
or
array[key]~=element;
without worrying about whether it's the first time for that key or not.
Users who want to know if the entry is there could then use 'in' (once it's fixed).
On 18/02/2012 04:13, Daniel Murphy wrote:
> Yeah, but that requires a design that fixes everything, including literals,
> template arg deduction, magic initialization etc.
>
> "Jonathan M Davis"<jmdavisProg@gmx.com> wrote in message
> news:mailman.514.1329537168.20196.digitalmars-d@puremagic.com...
>> On Saturday, February 18, 2012 14:46:21 Daniel Murphy wrote:
>>> Yes, that's the issue I'm talking about. In this case no comments means
>>> no
>>> disagreements. Unfortunately it requires changes to the AA api/codegen
>>> to
>>> fix, so it will probably be around until we move AAs completely into
>>> druntime.
>>
>> Which should probably be sorted out sooner rather than later given all of
>> the
>> bugs involved.
>>
>> - Jonathan M Davis
>
>
|
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Davis | "Ben Davis" <entheh@cantab.net> wrote in message news:jho2mf$2a1t$1@digitalmars.com... > Starting with magic initialisation then... > I meant a different magic initialization: int[int] aa = null; aa[3] = 7; // aa is magically not null any more > Is it vital that e[nonexistentKey] throw a RangeError, or could it just always return the type's default value if the key is absent? > This is what it does. > If you change that, then you can make assignment evaluate the RHS fully before even creating the LHS entry, and you won't in the process break the common case where people want to go > > count[key]++; > or > array[key]~=element; > > without worrying about whether it's the first time for that key or not. > This problem is just a bug in code generation from what I can tell, because lowering it manually results in the rhs being evaluated first. import std.stdio; int* getp() { writeln("1"); return new int; } void main() { *getp() += { writeln("2"); return 1; }(); } prints: 2 1 I have no idea where this is happening in the compiler. |
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | On 18/02/2012 13:22, Daniel Murphy wrote: > "Ben Davis"<entheh@cantab.net> wrote in message > news:jho2mf$2a1t$1@digitalmars.com... >> Starting with magic initialisation then... >> > > I meant a different magic initialization: > int[int] aa = null; > aa[3] = 7; // aa is magically not null any more > >> Is it vital that e[nonexistentKey] throw a RangeError, or could it just >> always return the type's default value if the key is absent? >> > This is what it does. It throws a RangeError. See the examples in my first message in this thread. I'm asking if changing the semantics to NOT throw a RangeError would be an option. >> If you change that, then you can make assignment evaluate the RHS fully >> before even creating the LHS entry, and you won't in the process break the >> common case where people want to go >> >> count[key]++; >> or >> array[key]~=element; >> >> without worrying about whether it's the first time for that key or not. >> > > This problem is just a bug in code generation from what I can tell, because > lowering it manually results in the rhs being evaluated first. > > import std.stdio; > > int* getp() > { > writeln("1"); > return new int; > } > > void main() > { > *getp() += { writeln("2"); return 1; }(); > } > > prints: > 2 > 1 > > I have no idea where this is happening in the compiler. Interesting - my gut feeling is that associative arrays are syntactic sugar and are being rewritten to use other constructs, and that rewriting is implementing a different execution order. |
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | On 18/02/2012 13:22, Daniel Murphy wrote:
> "Ben Davis"<entheh@cantab.net> wrote in message
> news:jho2mf$2a1t$1@digitalmars.com...
>> Starting with magic initialisation then...
>>
>
> I meant a different magic initialization:
> int[int] aa = null;
> aa[3] = 7; // aa is magically not null any more
I've seen some line-blurring between 'null' and 'empty' for dynamic arrays (non-associative). Specifically, I read that array.init returns null for both static and dynamic, but I think I also read that a dynamic array's default value is the empty array. I also observed that null~[1] == [1], and I wondered if actually 'null' becomes an empty array when cast to dynamic array and they're effectively the same thing.
If I'm right, then the same could be true for assoc arrays - that 'null' cast to an assoc array type becomes an empty assoc array. Which would explain the magic you're seeing.
|
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Davis | Self-correction: I evidently didn't read that array.init returns null for static arrays. But the point holds for dynamic ones.
On 18/02/2012 19:15, Ben Davis wrote:
> On 18/02/2012 13:22, Daniel Murphy wrote:
>> "Ben Davis"<entheh@cantab.net> wrote in message
>> news:jho2mf$2a1t$1@digitalmars.com...
>>> Starting with magic initialisation then...
>>>
>>
>> I meant a different magic initialization:
>> int[int] aa = null;
>> aa[3] = 7; // aa is magically not null any more
>
> I've seen some line-blurring between 'null' and 'empty' for dynamic
> arrays (non-associative). Specifically, I read that array.init returns
> null for both static and dynamic, but I think I also read that a dynamic
> array's default value is the empty array. I also observed that null~[1]
> == [1], and I wondered if actually 'null' becomes an empty array when
> cast to dynamic array and they're effectively the same thing.
>
> If I'm right, then the same could be true for assoc arrays - that 'null'
> cast to an assoc array type becomes an empty assoc array. Which would
> explain the magic you're seeing.
|
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Davis | Returning the default initializer of the value type when the key doesn't exist is a bad idea. Consider an integer, it's .init value is 0. If I want to check if a value of a key is zero I could easily end up with a silent bug: int[string] aa; aa["foobar"] = 5; if (aa["fobar"] == 0) { } // will always be true else { } |
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On 18/02/2012 20:54, Andrej Mitrovic wrote:
> Returning the default initializer of the value type when the key
> doesn't exist is a bad idea. Consider an integer, it's .init value is
> 0. If I want to check if a value of a key is zero I could easily end
> up with a silent bug:
>
> int[string] aa;
> aa["foobar"] = 5;
> if (aa["fobar"] == 0) { } // will always be true
> else { }
Isn't this the kind of situation where you should be using an enum for the key type? Or indeed just creating a struct or a class to hold the values you need? Especially as remove() already gives you 'silent bugs' if the key is misspelled.
|
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
On Saturday, February 18, 2012 21:54:52 Andrej Mitrovic wrote:
> Returning the default initializer of the value type when the key doesn't exist is a bad idea. Consider an integer, it's .init value is 0. If I want to check if a value of a key is zero I could easily end up with a silent bug:
>
> int[string] aa;
> aa["foobar"] = 5;
> if (aa["fobar"] == 0) { } // will always be true
> else { }
Agreed. The fact that C++ did something like this with std::map was one of its big mistakes IMHO.
- Jonathan M Davis
|
February 18, 2012 Re: When are associative arrays meant to throw a RangeError? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Davis | On 18/02/2012 21:42, Ben Davis wrote:
> On 18/02/2012 20:54, Andrej Mitrovic wrote:
>> Returning the default initializer of the value type when the key
>> doesn't exist is a bad idea. Consider an integer, it's .init value is
>> 0. If I want to check if a value of a key is zero I could easily end
>> up with a silent bug:
>>
>> int[string] aa;
>> aa["foobar"] = 5;
>> if (aa["fobar"] == 0) { } // will always be true
>> else { }
>
> Isn't this the kind of situation where you should be using an enum for
> the key type? Or indeed just creating a struct or a class to hold the
> values you need? Especially as remove() already gives you 'silent bugs'
> if the key is misspelled.
Oops, I mean misspelt :)
Another possible situation where you could already get a silent bug:
aa["foobar"] = 5;
...
aa["fobar"] = 6;
...
if (aa["foobar"]==5) {...}
Are you familiar with cases where an associative array is definitely the right tool for the job and you have a high risk of typos?
|
Copyright © 1999-2021 by the D Language Foundation