I have to say the AA changes are confusing to say the least.
With classes using 'lookup[key]' would create an (key,value) *entry* but not an *object*, so you still must check for null and create if necessary. The amount of code here is basically the same whether you use *in* or just aa[key]. Since you are using an object reference, you can change the object in the AA directly and there is no real need for pointers.
We now have 3 possibilities for AA which return classes:
1. Key is not in the AA, must check for this or Exception thrown.
2. Key is in the AA, but the reference stored there is null.
3. Key is in the AA, reference points to an object.
void CallMethod( MyClass c, int key, MyClass[int] lookup )
{
MyClass* ptr = (key in lookup);
if ( ptr is null ) lookup[key] = new MyClass();
MyClass ref = lookup[key];
if ( ref is null )
{
ref = new MyClass();
lookup[key]= ref;
}
ref.Method();
}
This is starting to make C++ look clean.
Structs on the other hand are supposed to be implicitly created.
They are *values* not objects.
So now we have 2 coding idioms/paradigms for structs:
1. Implicitly create when declared in code.
struct S {
int n = 99;
void callme(){ n++ ; }
}
S var1, var2, var3; // created as declared
var1.callme(); // no problem, I want the defaults, I defined them
2. Struct value in an AA.
S[int] lookup;
S[100].callme() ; //Now this statement requires 7-10 lines of code.
All this because someone was concerned with a double lookup the *first time* an object isnt found in the AA? Semantical madness over something that isnt even a real deficiency.
Premature optimization is a root cause of bad programming, because you end up making hard to follow code in attempts to optimize before you even know what is slow.
This is premature optimization at the *language level*.
-DavidM

In article <db0p66$vfj$1@digitaldaemon.com>, David Medlock says...
>>I have to say the AA changes are confusing to say the least.
>>With classes using 'lookup[key]' would create an (key,value) *entry* but not an *object*, so you still must check for null and create if necessary. The amount of code here is basically the same whether you use *in* or just aa[key]. Since you are using an object reference, you can change the object in the AA directly and there is no real need for pointers.
>>We now have 3 possibilities for AA which return classes:
>>1. Key is not in the AA, must check for this or Exception thrown.
>2. Key is in the AA, but the reference stored there is null.
>3. Key is in the AA, reference points to an object.
>>void CallMethod( MyClass c, int key, MyClass[int] lookup )
>{
> MyClass* ptr = (key in lookup);
> if ( ptr is null ) lookup[key] = new MyClass();
>> MyClass ref = lookup[key];
> if ( ref is null )
> {
> ref = new MyClass();
> lookup[key]= ref;
> }
> ref.Method();
>}
>>This is starting to make C++ look clean.
>>Structs on the other hand are supposed to be implicitly created. They are *values* not objects.
>>So now we have 2 coding idioms/paradigms for structs:
>1. Implicitly create when declared in code.
>>struct S {
> int n = 99;
> void callme(){ n++ ; }
>}
>>S var1, var2, var3; // created as declared
>var1.callme(); // no problem, I want the defaults, I defined them
>>2. Struct value in an AA.
>>S[int] lookup;
>S[100].callme() ; //Now this statement requires 7-10 lines of code.
>>All this because someone was concerned with a double lookup the *first time* an object isnt found in the AA? Semantical madness over something that isnt even a real deficiency.
>>Premature optimization is a root cause of bad programming, because you end up making hard to follow code in attempts to optimize before you even know what is slow.
>>This is premature optimization at the *language level*. -DavidM
Some of the code you mentioned has already been deprecated.
aa[key] now throws an exception if it does not exist. Thus aa[newkey] = new Class is now invalid. You must instead call aa.Add(key)
(See changes for DMD 126: Now throws an ArrayBoundsError if accessing an associative array with a key that is not already in the array. Previously, the key would be added to the array. )
Thus your code would change to something like this
:try {
: foo = aa[key];
:} catch ( Exception e ) {
: foo = aa.Add(key, new MyClass());
:} finally {
: foo.Method();
:}
Error handling sucks. Personally I think AA syntax is starting to transcend integral types. Since when does an integer throw an exception? I'm all for making AA's a part of phobos and separating them from the language syntax.
Also, these silly functions properties that are accessed like members are very confusing. Like this:
void HelloWorld(int foo) {
writeln("Hi world, I have %d foos", foo);
}
int foo;
foo.HelloWorld();
^-- AAARGGGH!!! Confusion ensues! I'd like to see this syntax go away too. It's not that much effort for people who want to extend the integer type to type this:
HelloWorld(foo); (which is less typing By the way, notice the lack of the extra
period)
Which is how it belongs since it's not part of the integer type, and you can't find it in the class file for integer.

Shammah Chancellor wrote:
> In article <db0p66$vfj$1@digitaldaemon.com>, David Medlock says...
> >>I have to say the AA changes are confusing to say the least.
>>>>With classes using 'lookup[key]' would create an (key,value) *entry* but not an *object*, so you still must check for null and create if necessary. The amount of code here is basically the same whether you use *in* or just aa[key]. Since you are using an object reference, you can change the object in the AA directly and there is no real need for pointers.
>>>>We now have 3 possibilities for AA which return classes:
>>>>1. Key is not in the AA, must check for this or Exception thrown.
>>2. Key is in the AA, but the reference stored there is null.
>>3. Key is in the AA, reference points to an object.
>>>>void CallMethod( MyClass c, int key, MyClass[int] lookup )
>>{
>> MyClass* ptr = (key in lookup);
>> if ( ptr is null ) lookup[key] = new MyClass();
>>>> MyClass ref = lookup[key];
>> if ( ref is null )
>> {
>> ref = new MyClass();
>> lookup[key]= ref;
>> }
>> ref.Method();
>>}
>>>>This is starting to make C++ look clean.
>>>>Structs on the other hand are supposed to be implicitly created.
>>They are *values* not objects.
>>>>So now we have 2 coding idioms/paradigms for structs:
>>1. Implicitly create when declared in code.
>>>>struct S {
>> int n = 99;
>> void callme(){ n++ ; }
>>}
>>>>S var1, var2, var3; // created as declared
>>var1.callme(); // no problem, I want the defaults, I defined them
>>>>2. Struct value in an AA.
>>>>S[int] lookup;
>>S[100].callme() ; //Now this statement requires 7-10 lines of code.
>>>>All this because someone was concerned with a double lookup the *first time* an object isnt found in the AA? Semantical madness over something that isnt even a real deficiency.
>>>>Premature optimization is a root cause of bad programming, because you end up making hard to follow code in attempts to optimize before you even know what is slow.
>>>>This is premature optimization at the *language level*.
>>-DavidM
> > > Some of the code you mentioned has already been deprecated.
> > aa[key] now throws an exception if it does not exist. Thus aa[newkey] = new
> Class is now invalid. You must instead call aa.Add(key)
>
Where is this documented?
http://www.digitalmars.com/d/arrays.html#associative
I see examples of
int[char[]] b; // associative array b of ints that are
// indexed by an array of characters.
// The KeyType is char[]
b["hello"] = 3; // set value associated with key "hello" to 3
> (See changes for DMD 126: Now throws an ArrayBoundsError if accessing an
> associative array with a key that is not already in the array. Previously, the
> key would be added to the array. )
> > Thus your code would change to something like this
> > :try {
> : foo = aa[key];
> :} catch ( Exception e ) {
> : foo = aa.Add(key, new MyClass());
> :} finally {
> : foo.Method();
> :}
> > Error handling sucks. Personally I think AA syntax is starting to transcend
> integral types. Since when does an integer throw an exception? I'm all for
> making AA's a part of phobos and separating them from the language syntax.
That is better than the previous semantics?
Compared to what? Java? I thought D was supposed to be attracting C/C++ programmers. Now we have checked exceptions?
> > > Also, these silly functions properties that are accessed like members are very
> confusing. Like this:
> > > void HelloWorld(int foo) {
> writeln("Hi world, I have %d foos", foo);
> }
> > int foo;
> > foo.HelloWorld();
> > ^-- AAARGGGH!!! Confusion ensues! I'd like to see this syntax go away too.
> It's not that much effort for people who want to extend the integer type to type
> this:
> > HelloWorld(foo); (which is less typing By the way, notice the lack of the extra
> period)
> > Which is how it belongs since it's not part of the integer type, and you can't
> find it in the class file for integer.
> > >
I agree you can go overboard with built in methods, however for templates they are more valuable because they can be overloaded in a class, whereas you cannot overload a specialized operator like *in*.

> void CallMethod( MyClass c, int key, MyClass[int] lookup )
> {
> MyClass* ptr = (key in lookup);
> if ( ptr is null ) lookup[key] = new MyClass();
>> MyClass ref = lookup[key];
> if ( ref is null )
> {
> ref = new MyClass();
> lookup[key]= ref;
> }
> ref.Method();
> }
Once the bug that you found with & is fixed the above can be rewritten as
void CallMethod( int key, MyClass[int] lookup )
{
MyClass* ptr = &lookup[key];
if ( !*ptr ) *ptr = new MyClass;
*ptr.Method();
}
> This is starting to make C++ look clean.
Again assuming the & bug is fixed the C++ code
map<A,B> x;
B& ref = x[a];
can be rewritten to the D code
B[A] x;
B* ref = &x[a];
That is about as simple as one can expect.
> Structs on the other hand are supposed to be implicitly created. They are *values* not objects.
>> So now we have 2 coding idioms/paradigms for structs:
> 1. Implicitly create when declared in code.
>> struct S {
> int n = 99;
> void callme(){ n++ ; }
> }
>> S var1, var2, var3; // created as declared
> var1.callme(); // no problem, I want the defaults, I defined them
>> 2. Struct value in an AA.
>> S[int] lookup;
> S[100].callme() ; //Now this statement requires 7-10 lines of code.
>> All this because someone was concerned with a double lookup the *first time* an object isnt found in the AA? Semantical madness over something that isnt even a real deficiency.
>> Premature optimization is a root cause of bad programming, because you end up making hard to follow code in attempts to optimize before you even know what is slow.
>> This is premature optimization at the *language level*. -DavidM
Somewhere I had read that C++ chose the lookup-and-insert behavior because throwing an exception was too slow and has spotty support. In any case I know BS said that operator[] returns a reference because returning the value is too slow. So there are a couple of C++ examples where performance drove the design.

Ben Hinkle wrote:
>>void CallMethod( MyClass c, int key, MyClass[int] lookup )
>>{
>> MyClass* ptr = (key in lookup);
>> if ( ptr is null ) lookup[key] = new MyClass();
>>>> MyClass ref = lookup[key];
>> if ( ref is null )
>> {
>> ref = new MyClass();
>> lookup[key]= ref;
>> }
>> ref.Method();
>>}
> > > Once the bug that you found with & is fixed the above can be rewritten as
> void CallMethod( int key, MyClass[int] lookup )
> {
> MyClass* ptr = &lookup[key];
> if ( !*ptr ) *ptr = new MyClass;
> *ptr.Method();
> }
> > > >>This is starting to make C++ look clean.
> > > Again assuming the & bug is fixed the C++ code
> map<A,B> x;
> B& ref = x[a];
> can be rewritten to the D code
> B[A] x;
> B* ref = &x[a];
> That is about as simple as one can expect.
> > That's beginning to look like C++.
Besides you haven't shown how that is superior to the old way.
What if I want value semantics and not call by reference?
(Which is the whole point of using a struct vs a class )
B* ref = &x[a];
B temp = ref[0];
// now I can use my local copy and reinsert it if needed
// versus
B temp = x[a];
The point is the change as made the code *more* complex, with zero benefits whatsoever. If the double lookup is a non-issue because it only matters when the value is null (ie the first time).
If you look up the *in stinks* thread, Matthew starts with complaints that the in operator returned a pointer. I actually agree with his sentiment, foreach(collections), object references(classes) and out parameters(for structs and other values) are superior to pointers.
http://www.digitalmars.com/d/archives/digitalmars/D/18450.html
Now pointers are *required*, and the code to access structures is longer(my example) or messy(your example)!!
The better alternative to *in* is a method:
B value;
if ( x.get( in a, out value ) ) { value.dostuff(); }
That is as simple as it gets, no pointers, can still use the create semantics, and if 'x' is a template alias, the x can implement .get(...) and still function with the don't create semantics.
I can't overload your example.
-DavidM

In article <db0ucs$14fp$1@digitaldaemon.com>, Ben Hinkle says...
>>> void CallMethod( MyClass c, int key, MyClass[int] lookup )
>> {
>> MyClass* ptr = (key in lookup);
>> if ( ptr is null ) lookup[key] = new MyClass();
>>>> MyClass ref = lookup[key];
>> if ( ref is null )
>> {
>> ref = new MyClass();
>> lookup[key]= ref;
>> }
>> ref.Method();
>> }
>>Once the bug that you found with & is fixed the above can be rewritten as
>void CallMethod( int key, MyClass[int] lookup )
>{
> MyClass* ptr = &lookup[key];
> if ( !*ptr ) *ptr = new MyClass;
> *ptr.Method();
>}
This will no longer work as lookup[key] will throw an exception since of creating the key since DMD 0.126. If Add will replace existing values, or if there is a Replace method then you could still simplify it to something very close to what you have.

"David Medlock" <noone@nowhere.com> wrote in message news:db0vub$15ot$1@digitaldaemon.com...> Ben Hinkle wrote:
>>>>void CallMethod( MyClass c, int key, MyClass[int] lookup )
>>>{
>>> MyClass* ptr = (key in lookup);
>>> if ( ptr is null ) lookup[key] = new MyClass();
>>>>>> MyClass ref = lookup[key];
>>> if ( ref is null )
>>> {
>>> ref = new MyClass();
>>> lookup[key]= ref;
>>> }
>>> ref.Method();
>>>}
>>>>>> Once the bug that you found with & is fixed the above can be rewritten as
>> void CallMethod( int key, MyClass[int] lookup )
>> {
>> MyClass* ptr = &lookup[key];
>> if ( !*ptr ) *ptr = new MyClass;
>> *ptr.Method();
>> }
>>>>>>>>>This is starting to make C++ look clean.
>>>>>> Again assuming the & bug is fixed the C++ code
>> map<A,B> x;
>> B& ref = x[a];
>> can be rewritten to the D code
>> B[A] x;
>> B* ref = &x[a];
>> That is about as simple as one can expect.
>>>>> That's beginning to look like C++.
> Besides you haven't shown how that is superior to the old way.
I'm not sure what you mean by "old way". Can you be more specific?
> What if I want value semantics and not call by reference?
> (Which is the whole point of using a struct vs a class )
> B* ref = &x[a];
> B temp = ref[0];
> // now I can use my local copy and reinsert it if needed
>> // versus
>> B temp = x[a];
>> The point is the change as made the code *more* complex, with zero benefits whatsoever. If the double lookup is a non-issue because it only matters when the value is null (ie the first time).
umm - "zero benefit"? whatever...
I agree it would be nice to have an explicit method to insert-and-lookup
when that is what one wants as was discussed in the posts on the bug thread
about &.
> If you look up the *in stinks* thread, Matthew starts with complaints that the in operator returned a pointer. I actually agree with his sentiment, foreach(collections), object references(classes) and out parameters(for structs and other values) are superior to pointers.
>> http://www.digitalmars.com/d/archives/digitalmars/D/18450.html>> Now pointers are *required*, and the code to access structures is longer(my example) or messy(your example)!!
>> The better alternative to *in* is a method:
>> B value;
> if ( x.get( in a, out value ) ) { value.dostuff(); }
>> That is as simple as it gets, no pointers, can still use the create semantics, and if 'x' is a template alias, the x can implement .get(...) and still function with the don't create semantics.
Various posts (I included it in my API requests) had what you call "get" by the name "contains" (though to be honest I've forgotten the details). I personally don't have anything against pointers, though, so the current 'in' is ok with me.
> I can't overload your example.
I, too, would like more overload control than what is available today. See the posts about opIndexMutable and such started by Kevin Bealer, for example.

>That's beginning to look like C++.
>Besides you haven't shown how that is superior to the old way.
>>What if I want value semantics and not call by reference?
>(Which is the whole point of using a struct vs a class )
>B* ref = &x[a];
>B temp = ref[0];
> // now I can use my local copy and reinsert it if needed
>>// versus
>>B temp = x[a];
>>The point is the change as made the code *more* complex, with zero benefits whatsoever. If the double lookup is a non-issue because it only matters when the value is null (ie the first time).
>>If you look up the *in stinks* thread, Matthew starts with complaints that the in operator returned a pointer. I actually agree with his sentiment, foreach(collections), object references(classes) and out parameters(for structs and other values) are superior to pointers.
>>http://www.digitalmars.com/d/archives/digitalmars/D/18450.html>>Now pointers are *required*, and the code to access structures is longer(my example) or messy(your example)!!
>>The better alternative to *in* is a method:
>>B value;
>if ( x.get( in a, out value ) ) { value.dostuff(); }
>>That is as simple as it gets, no pointers, can still use the create
>semantics, and if 'x' is a template alias, the x can implement .get(...)
>and still function with the don't create semantics.
>I can't overload your example.
>>-DavidM
Not to mention we have some context dependant syntax going on there with the in keyword being used for different things in different places. IE:
int foo( in int a, inout int[int] foo ) {
MyClass *arg = a in foo;
}
See the different use? I vote to make AA it's own class....

>>Once the bug that you found with & is fixed the above can be rewritten as
>>void CallMethod( int key, MyClass[int] lookup )
>>{
>> MyClass* ptr = &lookup[key];
>> if ( !*ptr ) *ptr = new MyClass;
>> *ptr.Method();
>>}
>> This will no longer work as lookup[key] will throw an exception since of
> creating the key since DMD 0.126. If Add will replace existing values, or
> if
> there is a Replace method then you could still simplify it to something
> very
> close to what you have.
lookup[key] does not throw if the result is expected to be an lvalue. The problem is that there is a bug in dmd that the & operator isn't among those operators that are flagged as expecting an lvalue. See David's earlier post in this newsgroup and see my post about it in the bugs newsgroup.