View mode: basic / threaded / horizontal-split · Log in · Help
July 12, 2005
Re: AA revisited
Ben Hinkle wrote:

> "David Medlock" <noone@nowhere.com> wrote in message 
>>
>>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...

Since you see a benefit, please tell me what it is.  It still escapes me.

-DavidM
July 12, 2005
Re: AA revisited
"David Medlock" <noone@nowhere.com> wrote in message 
news:db11io$174u$1@digitaldaemon.com...
> Ben Hinkle wrote:
>
>> "David Medlock" <noone@nowhere.com> wrote in message
>>>
>>>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...
>
> Since you see a benefit, please tell me what it is.  It still escapes me.
>
> -DavidM
>

* more intuitive for most users (ie - those not assuming AAs are stl::map)
* more like Java, C#, Ruby (which return null and only work for classes) and 
Python (which errors)
* means regular rvalue lookup does not modify the array which means reading 
is thread-safe
* consistent with dynamic and static arrays where requesting a value not in 
the array throws
July 12, 2005
Re: AA revisited
In article <db118h$16qm$1@digitaldaemon.com>, Ben Hinkle says...
>
>>>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. 
>

Hrm.. It didn't say that in the changelog, but i'll believe you. (See the
changelog for DMD 0.126)

Shouldn't this work:

void CallMethod( MyClass c, int key, MyClass[int]  lookup )
{
MyClass *ref = key in lookup ;
MyClass ptr;

if ( !ref || !*ref )  lookup[key] = ptr = new MyClass();
else ptr = *ref;
ptr.Method();
}

I can't really see a better solution.  Adding or ignoring if exists doesn't seem
good.  IE:  aa.CreateIfNotExists( key, new MyClass() );  This will always create
a new MyClass even if there is no new key made.
July 12, 2005
Re: AA revisited
Generally speaking effective AA implementation should have three methods:

bool aa.search( key , &value );
-- const (immutable) method.
-- D: key in aa;

aa.insert( key, value );
-- mutable method, 1) replaces value under
  the key if it is there or 2) inserts new key.value
  pair into the assosiation if does not exist.
-- D: aa[key] = value;

value aa.get( key, function(key,value) ctor );
-- mutable method, if value is not in collection
   calls ctor to construct value for the new pair.
   always returns initialized value.
-- ???

This is canonically full set of operations.

In presence of default initializers for types in D last 'get'
method could be substituted by x = aa[key] with
silent construction of new value if needed.
Not so convenient but reasonable compromise.

Andrew.
July 12, 2005
Re: AA revisited
"Shammah Chancellor" <Shammah_member@pathlink.com> wrote in message 
news:db14mg$19qo$1@digitaldaemon.com...
> In article <db118h$16qm$1@digitaldaemon.com>, Ben Hinkle says...
>>
>>>>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.
>>
>
> Hrm.. It didn't say that in the changelog, but i'll believe you. (See the
> changelog for DMD 0.126)

The details about AAs are still largely undocumented, that's true. Walter 
hasn't been very vocal about where he intends to go with AAs but that isn't 
unusual.

> Shouldn't this work:
>
> void CallMethod( MyClass c, int key, MyClass[int]  lookup )
> {
> MyClass *ref = key in lookup ;
> MyClass ptr;
>
> if ( !ref || !*ref )  lookup[key] = ptr = new MyClass();
> else ptr = *ref;
> ptr.Method();
> }
>
> I can't really see a better solution.  Adding or ignoring if exists 
> doesn't seem
> good.  IE:  aa.CreateIfNotExists( key, new MyClass() );  This will always 
> create
> a new MyClass even if there is no new key made.

Correct - that will work today. However I still hope Walter makes 
&lookup[key] insert if not present.
July 12, 2005
Re: AA revisited
Ben Hinkle wrote:

 > * more intuitive for most users (ie - those not assuming AAs are 
stl::map)
This is subjective of course, but aren't most D ppl coming from C++?

See my post about call-by-value vs call-by-reference. We added 1 new 
condition for struct/values and 1 new condition for classes.
More intuitive for a total of 5 conditions vs 3 before?

IMO declaring:

MyClass[int] aa;
MyClass c = aa[100];

should give me the default for an uninitialized MyClass object, null.
I don't think an Exception is warranted, because I expect some values 
won't exist yet, but that does not make the key invalid!

> * more like Java, C#, Ruby (which return null and only work for classes) and 
> Python (which errors)
As you say, Java, C# and Ruby don't have a builtin and do not work with 
non-classes. Their containers are themselves classes, which could be 
implemented in D also.

Python errors , while Lua returns null:

-- lua code
a = lookup[100] or createObject(); -- very succinct
--

Plus python has the get(..) method we discussed.
Not much Python code try...catches around the lookup I'd bet.

> * means regular rvalue lookup does not modify the array which means reading 
> is thread-safe
Thread safe code should be in a thread safe class/module.  I don't think 
thread safety should dictate the lowest common denominator for a 
language which is already pretty wide open, thread-safety wise.

> * consistent with dynamic and static arrays where requesting a value not in 
> the array throws 
Throwing exceptions are supposed to be for unusual circumstances, not 
normal execution.  I would hope D isn't moving towards checked Exceptions.

In any case, I sincerely hope Walter adds a get()/lookup() builtin.

Thanks for the points, Ben.

Please do not mistake my passion for a pragmatic D as anything else.
-DavidM
July 12, 2005
Re: AA revisited
Forgot to mention:

To be consistent with Ben's requirement:
"* consistent with dynamic and static arrays where requesting a value not in
the array throws"

AA should have read-only equivalent - read-only AA.
such AA# has method x = aa[key] implemented differently -
it throws if key is not in collection. 'insert' method shall be disabled and
and any attempt to call must be prevented at compile time.

Andrew.
July 12, 2005
Re: AA revisited
"David Medlock" <noone@nowhere.com> wrote in message 
news:db15vt$1aqu$1@digitaldaemon.com...
> Ben Hinkle wrote:
>
>  > * more intuitive for most users (ie - those not assuming AAs are 
> stl::map)
> This is subjective of course, but aren't most D ppl coming from C++?
>
> See my post about call-by-value vs call-by-reference. We added 1 new 
> condition for struct/values and 1 new condition for classes.
> More intuitive for a total of 5 conditions vs 3 before?
>
> IMO declaring:
>
> MyClass[int] aa;
> MyClass c = aa[100];
>
> should give me the default for an uninitialized MyClass object, null.
> I don't think an Exception is warranted, because I expect some values 
> won't exist yet, but that does not make the key invalid!
>
>> * more like Java, C#, Ruby (which return null and only work for classes) 
>> and Python (which errors)
> As you say, Java, C# and Ruby don't have a builtin and do not work with 
> non-classes. Their containers are themselves classes, which could be 
> implemented in D also.
>
> Python errors , while Lua returns null:
>
> -- lua code
> a = lookup[100] or createObject(); -- very succinct
> --
>
> Plus python has the get(..) method we discussed.
> Not much Python code try...catches around the lookup I'd bet.
>
>> * means regular rvalue lookup does not modify the array which means 
>> reading is thread-safe
> Thread safe code should be in a thread safe class/module.  I don't think 
> thread safety should dictate the lowest common denominator for a language 
> which is already pretty wide open, thread-safety wise.

Agree.

>
>> * consistent with dynamic and static arrays where requesting a value not 
>> in the array throws
> Throwing exceptions are supposed to be for unusual circumstances, not 
> normal execution.  I would hope D isn't moving towards checked Exceptions.

Agree. "key does not exist" is always expected result for AA.
And constant/immutable AAs must have only 'in' (or immutable get)
method available to caller.

>
> In any case, I sincerely hope Walter adds a get()/lookup() builtin.
>
> Thanks for the points, Ben.
>
> Please do not mistake my passion for a pragmatic D as anything else.
> -DavidM
July 12, 2005
Re: AA revisited
>>> * consistent with dynamic and static arrays where requesting a value not 
>>> in the array throws
>> Throwing exceptions are supposed to be for unusual circumstances, not 
>> normal execution.  I would hope D isn't moving towards checked 
>> Exceptions.
>
> Agree. "key does not exist" is always expected result for AA.
> And constant/immutable AAs must have only 'in' (or immutable get)
> method available to caller.

I don't actually mind returning init on failure but my preference is 
throwing. I think Matthew was the biggest proponent of throwing - but my 
memory is vague. Here's a silly example but imagine an AA indexed by country 
with enum {Invade, Sanctions} and you look up, say, Iraq and no-one had 
thought about what to do about Iraq yet. That might actually explain a few 
things. :-P
July 12, 2005
Re: AA revisited
"Ben Hinkle" <bhinkle@mathworks.com> wrote in message 
news:db19ia$1ead$1@digitaldaemon.com...
>>>> * consistent with dynamic and static arrays where requesting a value 
>>>> not in the array throws
>>> Throwing exceptions are supposed to be for unusual circumstances, not 
>>> normal execution.  I would hope D isn't moving towards checked 
>>> Exceptions.
>>
>> Agree. "key does not exist" is always expected result for AA.
>> And constant/immutable AAs must have only 'in' (or immutable get)
>> method available to caller.
>
> I don't actually mind returning init on failure but my preference is 
> throwing. I think Matthew was the biggest proponent of throwing - but my 
> memory is vague. Here's a silly example but imagine an AA indexed by 
> country with enum {Invade, Sanctions} and you look up, say, Iraq and 
> no-one had thought about what to do about Iraq yet. That might actually 
> explain a few things. :-P

:) Well, Canada prefer different enum values {Friend, Almost, 
NotYet}otherwise
example is good.

There are two distinct situations:
1)  immutable AA - List of keywords in compiler. It shouldn't be such 
entities as opIndex and opIndexAssign at all. Right?
2) dynamic AA - E.g. word counting:  Both opIndex and opIndexAssign should 
be there.

dictionary[word]++;

in wc2.d looked more elegantly than

if (!(word in dictionary))
  dictionary[word] = 0;
else
  ++dictionary[word];

isn't it?

Andrew.
1 2 3 4
Top | Discussion index | About this forum | D home