www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - hash lookup make dummy hash entry

reply bero <berobero users.sourceforge.net> writes:
hash lookup make dummy hash entry

---
/* hash bug */
int main(char[][] args)
{
	char[][char[]] hash;

	printf("%d\n",hash.length);

	hash["foo"] = "foo";

	printf("%d\n",hash.length);

	hash["bar"] = "bar";

	printf("%d\n",hash.length); // print 2

	char[] val = hash["baz"]; // lookups make ' hash["baz"] = null ' new entry

	printf("%d\n",hash.length); // print 3
	return 0;
}
---

Both hash lookup and setting generate "_aaGet" function call
and set hash[key]=0 when lookup.
Feb 08 2005
parent reply =?UTF-8?B?QW5kZXJzIEYgQmrDtnJrbHVuZA==?= <afb algonet.se> writes:
bero wrote:

 hash lookup make dummy hash entry

This is a well known bug / behaviour... You currently need to use the "in" operator: char[] val = "baz" in hash ? hash["baz"] : ""; It's on purpose, but nobody knows why ? --anders
Feb 08 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 08 Feb 2005 19:43:28 +0100, Anders F Björklund <afb algonet.se>  
wrote:
 bero wrote:

 hash lookup make dummy hash entry

This is a well known bug / behaviour... You currently need to use the "in" operator: char[] val = "baz" in hash ? hash["baz"] : ""; It's on purpose, but nobody knows why ?

I believe this thread (if followed far enough) contains the reasoning: digitalmars.D.dtl/124 If you have an AA of 'reference' types then you can return null on a non-existant entry. If you have an AA of 'value' types i.e. int, long, struct then you can't return null, but you can return Type.init, however: how do you tell that apart from a existing entry with that same value? So, either the AA creates an entry, or it throws an exception. Personally I think the latter is the correct default behaviour. Really the only reason not to use "if (x in aa)" all the time is that it in most cases causes a double lookup eg. if (x in aa) { y = aa[x]; ..etc.. } In the thread above I proposed some helper functions to avoid the double lookup and Ben even wrote some of them. bool contains(key_type key, out value_type value); --returns existance of value, assigns 'value' if found bool contains(key_type key, out index_type at); --returns existance of value, assigns 'at' to location which can then be used to get/replace/add an item. Regan
Feb 08 2005
next sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
Which is why it was changed recently so you can do this:

y = x in aa;
if (y)
{
    ...
}

Which of course is a bit different, but is only a single lookup all the 
same.

-[Unknown]


 Really the only reason not to use "if (x in aa)" all the time is that 
 it  in most cases causes a double lookup eg.
 
 if (x in aa) {
   y = aa[x];
   ..etc..
 }

Feb 08 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 08 Feb 2005 12:58:47 -0800, Unknown W. Brackets  
<unknown simplemachines.org> wrote:
 Which is why it was changed recently so you can do this:

 y = x in aa;
 if (y)
 {
     ...
 }

 Which of course is a bit different, but is only a single lookup all the  
 same.

True. This was a good idea IMO. However, I'm still not convinced the behaviour of aa["key"] for a missing value is 'correct'. It seems to cause bugs, at least for begginners un-used to the behaviour and may even cause the odd problem for the more experienced. That said, I'm not convinced an exception is all that 'nice' either. Regan
Feb 08 2005
prev sibling next sibling parent reply =?UTF-8?B?QW5kZXJzIEYgQmrDtnJrbHVuZA==?= <afb algonet.se> writes:
Regan Heath wrote:

 hash lookup make dummy hash entry

It's on purpose, but nobody knows why ?

I believe this thread (if followed far enough) contains the reasoning: digitalmars.D.dtl/124 If you have an AA of 'reference' types then you can return null on a non-existant entry.

Perfectly alright.
 If you have an AA of 'value' types i.e. int, long, struct then you 
 can't  return null, but you can return Type.init, however: how do you 
 tell that  apart from a existing entry with that same value?

By using the "in" operator, in case you care about the difference ? In silly languages, like Java's JDBC interface for instance, they have "helper" functions like isNull or wrap primitives in objects. (both of which could still be emulated in D with some extra code)
 So, either the AA creates an entry, or it throws an exception.
 Personally I think the latter is the correct default behaviour.

It would be perfectly acceptible for the AA to: 1) *not* create something upon reading 2) *not* throw an annoying exception But to just return Type.init and be done with it ? This enables the hashes to work as unlimited arrays, in that they are all inited to the default value but do not throw ArrayBoundsError (since there is none)
 Really the only reason not to use "if (x in aa)" all the time is that 
 it  in most cases causes a double lookup eg.
 
 if (x in aa) {
   y = aa[x];
   ..etc..
 }

Walter changed the language, so that "in" now returns a *pointer* (there are still a few bugs in the new implementation, but anyway) This means you can now do: if ((p = x in aa) != null) { y = *p; } which avoids the double-lookup, at the expense of readability... Just don't try this with function delegates, and a few other AA types. (there you still need the double lookup like above, at least for now)
 In the thread above I proposed some helper functions to avoid the 
 double  lookup and Ben even wrote some of them.

Shouldn't be needed, with the new "in" implementation (when debugged) Never mind re-introducing pointers, and mixing booleans and pointers. But the horribly confusing "create entries when reading" should die! Then the only thing left to do is to avoid the "delete" keyword... --anders
Feb 08 2005
next sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
I'm afraid that I, apparently unlike you, use associative arrays with 
many values in them - including some that are Type.init.

To have it return Type.init and not create the entry seems much worse to 
me than just creating the darn thing (which mind you, I don't quite like 
either.)

-[Unknown]


 But to just return Type.init and be done with it ?

Feb 08 2005
parent reply =?UTF-8?B?QW5kZXJzIEYgQmrDtnJrbHVuZA==?= <afb algonet.se> writes:
Unknown W. Brackets wrote:

 I'm afraid that I, apparently unlike you, use associative arrays with 
 many values in them - including some that are Type.init.

So use "in" to separate between them ? Works just fine. Or do you mean you actually use hash[key] to set them ? --anders
Feb 09 2005
next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 09 Feb 2005 11:04:29 +0100, Anders F Björklund <afb algonet.se>  
wrote:
 Unknown W. Brackets wrote:

 I'm afraid that I, apparently unlike you, use associative arrays with  
 many values in them - including some that are Type.init.

So use "in" to separate between them ? Works just fine.

Yes it works, but it's not 'nice'. You are relegated to using pointers for basic types, that seems contrary to the fact that they're 'basic' types.
 Or do you mean you actually use hash[key] to set them ?

I don't follow, why is this an issue? Regan
Feb 09 2005
parent =?ISO-8859-15?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Regan Heath wrote:

 I'm afraid that I, apparently unlike you, use associative arrays 
 with  many values in them - including some that are Type.init.

So use "in" to separate between them ? Works just fine.

Yes it works, but it's not 'nice'. You are relegated to using pointers for basic types, that seems contrary to the fact that they're 'basic' types.

You can still use "in" like in a so called boolean expression, like before. Won't matter that it's a pointer now and not bit ? And then use hash[key] to retrieve it. Avoids the pointer, but does mean a double lookup on the hash key is being made. If you want the fast route, just use the pointer for both.
 Or do you mean you actually use hash[key] to set them ?

I don't follow, why is this an issue?

The bug we're talking about is that when you read hash[key], the value gets set to .init - and unless someone is actually using this "feature", it should be removed from the language. Since it's really confusing and annoying to everyone else... --anders
Feb 09 2005
prev sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
Point is, if I do this:

...
char[int] test;

test[4] = 0;
return test[5];
...

I DO NOT want 0, because that would only confuse my programming.... 
that's all I meant.  If it has to return 0, it should set that too. 
Only way that makes sense, imho.

-[Unknown]


 Or do you mean you actually use hash[key] to set them ?

Feb 09 2005
parent =?UTF-8?B?QW5kZXJzIEYgQmrDtnJrbHVuZA==?= <afb algonet.se> writes:
Unknown W. Brackets wrote:

 Point is, if I do this:
 
 ...
 char[int] test;
 
 test[4] = 0;
 return test[5];
 ...

How cute, char's don't get the .init value, but instead just a zero. Now, that's.... totally useless:
 	// Not found, create new elem
 	//printf("create new one\n");
 	e = cast(aaA *) cast(void*) new byte[aaA.sizeof + keysize + valuesize];
 	memcpy(e + 1, pkey, keysize);
 	e.hash = key_hash;
 	*pe = e;

Would have more sense if it was .init ?
 I DO NOT want 0, because that would only confuse my programming.... 
 that's all I meant.  If it has to return 0, it should set that too. Only 
 way that makes sense, imho.

Had you gotten a '\xFF', maybe it could have worked for you too ? But if you keep on relying on side effects like that, I guess the current behaviour is working as you like. Either way, calling opIndex on an array with a nonexisting key should be defined and documentated properly. But out of the three "plausible" solutions to what this op should do: 1) return 0 or -1 or null or some odd value like that 2) throw an exception, KeyNotFoundException or whatever 3) silently create a new zero-entry and return it I find the current behaviour (3) to the *most* confusing... --anders
Feb 10 2005
prev sibling next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 08 Feb 2005 22:04:57 +0100, Anders F Björklund <afb algonet.se>  
wrote:
 Regan Heath wrote:

 hash lookup make dummy hash entry

It's on purpose, but nobody knows why ?

digitalmars.D.dtl/124 If you have an AA of 'reference' types then you can return null on a non-existant entry.

Perfectly alright.

Agreed.
 If you have an AA of 'value' types i.e. int, long, struct then you  
 can't  return null, but you can return Type.init, however: how do you  
 tell that  apart from a existing entry with that same value?

By using the "in" operator, in case you care about the difference ?

Forcing you to either use a double lookup, or a pointer... it just seems to me like there has to be a better solution, I mean these are basic types after all, my gut feeling is that it should be easy/simple and it's not.
 In silly languages, like Java's JDBC interface for instance, they
 have "helper" functions like isNull or wrap primitives in objects.
 (both of which could still be emulated in D with some extra code)

I dislike these wrappers in general.
 So, either the AA creates an entry, or it throws an exception.
 Personally I think the latter is the correct default behaviour.

It would be perfectly acceptible for the AA to: 1) *not* create something upon reading

Agreed.
 2) *not* throw an annoying exception

Agreed.
 But to just return Type.init and be done with it ?

This bugs me. I'd rather use a function: bool contains(key_type key, out value_type value); Which: 1. returned 'true' and assigned 'value' to the existing value. 2. returned 'false' and did nothing to 'value'. This works the same way for both reference and value types. I admit it doesn't work for structs, it's the whole "how do you copy a struct?" problem, however I'd argue that in this case it's better to use struct pointers, to avoid copying large blocks of memory. It's not a perfect solution, but it works well, and identically for everything but structs, so it seems the best soln to me.
 This enables the hashes to work as unlimited arrays,
 in that they are all inited to the default value but
 do not throw ArrayBoundsError (since there is none)

I don't think they should ever throw 'ArrayBoundsError'. If they throw anything it's 'NoSuchItemError' or something.
 Really the only reason not to use "if (x in aa)" all the time is that  
 it  in most cases causes a double lookup eg.
  if (x in aa) {
   y = aa[x];
   ..etc..
 }

Walter changed the language, so that "in" now returns a *pointer* (there are still a few bugs in the new implementation, but anyway) This means you can now do: if ((p = x in aa) != null) { y = *p; } which avoids the double-lookup, at the expense of readability... Just don't try this with function delegates, and a few other AA types. (there you still need the double lookup like above, at least for now)

It's a good solution, but it's not perfect as you say. Readability suffers, and we're forced to use pointers again, something I'm keen to avoid if at all possible.
 In the thread above I proposed some helper functions to avoid the  
 double  lookup and Ben even wrote some of them.

Shouldn't be needed, with the new "in" implementation (when debugged) Never mind re-introducing pointers, and mixing booleans and pointers.

I want to avoid re-introducing pointers, my solution does this by using an 'out' variable. I don't understand "mixing booleans and pointers", are you referring to "if (pointer)" statements?
 But the horribly confusing "create entries when reading" should die!

Agreed.
 Then the only thing left to do is to avoid the "delete" keyword...

Which has some (commonly percieved) odd behaviour all of it's own. Regan
Feb 08 2005
parent =?ISO-8859-15?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Regan Heath wrote:

 I'd rather use a function:
 bool contains(key_type key, out value_type value);
 
 Which:
 1. returned 'true' and assigned 'value' to the existing value.
 2. returned 'false' and did nothing to 'value'.
 
 This works the same way for both reference and value types.

Hashes are built-in types in D. Thus they don't need eg. functions, or it would be the same as it is implemented in Java Collections ?
 I don't think they should ever throw 'ArrayBoundsError'.
 If they throw anything it's 'NoSuchItemError' or something.

Doesn't matter, since you still need the double lookup then with "in", to avoid having it throw up all over the place.
 It's a good solution, but it's not perfect as you say. Readability  
 suffers, and we're forced to use pointers again, something I'm keen to  
 avoid if at all possible.

It's also cheerfully mixing those pointers with a boolean "in"
 Then the only thing left to do is to avoid the "delete" keyword...

Which has some (commonly percieved) odd behaviour all of it's own.

Well, compare: delete array[key], for different types of arrays... (dynamic int[] arrays where key is an int, with the associative) I suggested "out" myself. 1) it's a keyword 2) rhymes with "in" (and it could return a pointer to the item that it just removed) --anders
Feb 08 2005
prev sibling parent reply Nick <Nick_member pathlink.com> writes:
Walter changed the language, so that "in" now returns a *pointer*
(there are still a few bugs in the new implementation, but anyway)

This means you can now do: if ((p = x in aa) != null) { y = *p; }
which avoids the double-lookup, at the expense of readability...

Would it not be a better solution to have "in" return a bool, and instead have the compiler optimize away the double lookup? I'm no expert, so I don't know if this is even possible. Is it? Nick
Feb 09 2005
parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Nick wrote:

Walter changed the language, so that "in" now returns a *pointer*
(there are still a few bugs in the new implementation, but anyway)

This means you can now do: if ((p = x in aa) != null) { y = *p; }
which avoids the double-lookup, at the expense of readability...

Would it not be a better solution to have "in" return a bool, and instead have the compiler optimize away the double lookup? I'm no expert, so I don't know if this is even possible. Is it?

That's how it worked before, although it can't optimize the double lookup since it doesn't know that you are going to use it again... *I* still believe that in most cases you could just have done a: if ((y = aa[x) != y.init) { ... } and totally ignored the difference of whether x was "in" or not ? (it doesn't work with .init entries) You couldn't store "null" in in the old Java 1 class called Hashtable. Can't say it was ever a big problem ? (Java 2 Map does permit null keys) But you can't at the moment, since that will instead fill the hash up... (you can't do if(y = aa[x)), since "'=' does not give a boolean result") Which means that until the *bugs* has been addressed, you need to write: val = key in hash ? hash[key] : val.init; Instead of just: val = hash[key]; --anders
Feb 09 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 09 Feb 2005 11:01:17 +0100, Anders F Björklund <afb algonet.se>  
wrote:
 Nick wrote:

 Walter changed the language, so that "in" now returns a *pointer*
 (there are still a few bugs in the new implementation, but anyway)

 This means you can now do: if ((p = x in aa) != null) { y = *p; }
 which avoids the double-lookup, at the expense of readability...

and instead have the compiler optimize away the double lookup? I'm no expert, so I don't know if this is even possible. Is it?

That's how it worked before, although it can't optimize the double lookup since it doesn't know that you are going to use it again... *I* still believe that in most cases you could just have done a: if ((y = aa[x) != y.init) { ... } and totally ignored the difference of whether x was "in" or not ? (it doesn't work with .init entries)

You can do this for all cases where init.value == 'non existant'. In other words when you do not need to treat non existant as different to the init.value. That might be 'most' cases for you, it might not be for someone else.
 You couldn't store "null" in in the old Java 1 class called Hashtable.
 Can't say it was ever a big problem ?

What did it do/return when you requested a non existant element?
 (Java 2 Map does permit null keys)

null keys? or null values?
 But you can't at the moment, since that will instead fill the hash up...
 (you can't do if(y = aa[x)), since "'=' does not give a boolean result")


 Which means that until the *bugs* has been addressed, you need to write:
 val = key in hash ? hash[key] : val.init;

 Instead of just:
 val = hash[key];

Are you talking about java above, or D? Regan
Feb 09 2005
next sibling parent reply =?ISO-8859-15?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Regan Heath wrote:

 *I* still believe that in most cases you could just have done a:
 if ((y = aa[x) != y.init) { ... } and totally ignored the difference
 of whether x was "in" or not ? (it doesn't work with .init entries)

You can do this for all cases where init.value == 'non existant'. In other words when you do not need to treat non existant as different to the init.value. That might be 'most' cases for you, it might not be for someone else.

And they can just use the "in" logic first, and avoid getting .init ? Or if they do get a .init (0 or null or whatever), they can check with "in" if it existed as .init or if it didn't exist in the hash. But reading a value should not just create and store a blank one.
 You couldn't store "null" in in the old Java 1 class called Hashtable.
 Can't say it was ever a big problem ?

What did it do/return when you requested a non existant element?

It returned null. If you used null keys, it threw NullPointerExceptions Java 1:
 Returns:
     the value to which the key is mapped in this hashtable;
     null if the key is not mapped to any value in this hashtable. 

 (Java 2 Map does permit null keys)

null keys? or null values?

Both, I believe ? But they reworked the whole Java Collections a *lot*. Java 2:
 Returns the value to which the specified key is mapped in this
 identity hash map, or null if the map contains no mapping for
 this key. A return value of null does not necessarily indicate
 that the map contains no mapping for the key; it is also possible
 that the map explicitly maps the key to null. The containsKey
 method may be used to distinguish these two cases.

 Which means that until the *bugs* has been addressed, you need to write:
 val = key in hash ? hash[key] : val.init;

 Instead of just:
 val = hash[key];

Are you talking about java above, or D?

Back in D land, again. :-) No primitive hashes in Java, objects there. And in the current D implementation, reading a nonexisting key will create a new value of .init for the key, and return that. Thus, the need to use "in" - to avoid creating dummy hash entries. I fail to see why one wants a dummy new value or an exception. Maybe someone can give some example code that relies on either ? --anders
Feb 09 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 09 Feb 2005 23:21:30 +0100, Anders F Björklund <afb algonet.se>  
wrote:
 Regan Heath wrote:

 *I* still believe that in most cases you could just have done a:
 if ((y = aa[x) != y.init) { ... } and totally ignored the difference
 of whether x was "in" or not ? (it doesn't work with .init entries)

other words when you do not need to treat non existant as different to the init.value. That might be 'most' cases for you, it might not be for someone else.

And they can just use the "in" logic first, and avoid getting .init ?

Yes, but then they have a double lookup.
 Or if they do get a .init (0 or null or whatever), they can check
 with "in" if it existed as .init or if it didn't exist in the hash.

A double lookup.
 But reading a value should not just create and store a blank one.

I agree totally, I'm not arguing 'for' this behaviour at all. :) Sorry if I missled.
 You couldn't store "null" in in the old Java 1 class called Hashtable.
 Can't say it was ever a big problem ?


It returned null.

Could it store basic types i.e. 'int'?
 If you used null keys, it threw NullPointerExceptions

Sure, I can't really see a point in a null key.
 Java 1:
 Returns:
     the value to which the key is mapped in this hashtable;
     null if the key is not mapped to any value in this hashtable.


Thanks.
 (Java 2 Map does permit null keys)


Both, I believe ? But they reworked the whole Java Collections a *lot*.

I can understand null values, why do you want/need null keys?
 Java 2:
 Returns the value to which the specified key is mapped in this
 identity hash map, or null if the map contains no mapping for
 this key. A return value of null does not necessarily indicate
 that the map contains no mapping for the key; it is also possible
 that the map explicitly maps the key to null. The containsKey
 method may be used to distinguish these two cases.


Thanks.
 Which means that until the *bugs* has been addressed, you need to  
 write:
 val = key in hash ? hash[key] : val.init;

 Instead of just:
 val = hash[key];


Back in D land, again. :-) No primitive hashes in Java, objects there. And in the current D implementation, reading a nonexisting key will create a new value of .init for the key, and return that.

I know, I disagree with this behaviour.
 Thus, the need to use "in" - to avoid creating dummy hash entries.

Sure.
 I fail to see why one wants a dummy new value or an exception.

I don't want the former, I don't want the latter, however if they were our only choices I'd choose the latter. As you've said we have other choices: - use 'in' and pointers. To me that seems contrary to the idea that a basic type is just that basic, eg. int[char[]] aa; int *p; int v; //here we are trying to get the value of "fred" out of the aa without a double lookup. p = ("fred" in aa); v = *p; //not too bad I admit, less verbose than try { v = aa["fred"]; } catch(Exception e) { } Ahhh well, I guess all I'm saying is that: - I dislike the behaviour of v = aa["fred"] when "fred" does not exist, it seems to be the greater of the evils. - I dislike the soln we have to use to avoid a double lookup, but it appears to be the lesser of the evils.
 Maybe someone can give some example code that relies on either ?

Not I. Regan
Feb 09 2005
next sibling parent reply =?ISO-8859-15?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Regan Heath wrote:

 But reading a value should not just create and store a blank one.

I agree totally, I'm not arguing 'for' this behaviour at all. :) Sorry if I missled.

<phew>
 You couldn't store "null" in in the old Java 1 class called Hashtable.
 Can't say it was ever a big problem ?

What did it do/return when you requested a non existant element?

It returned null.

Could it store basic types i.e. 'int'?

Nope, like all collections in Java it can *only* handle Objects. That's why they have all the wrapper object types for primitives: Integer, Byte, Short, Long, Character, Float, Double, etc. And of course the String class is the default, for doing strings (doesn't really matter, since char[] is also an object in Java!) For the JDBC interface, they do a double approach: there is one Object-returning method, and one for each of the primitive types - including a boolean "wasNull" function to check for null values. http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html Quite different. (D does *not* want such wrapper classes/methods)
 I fail to see why one wants a dummy new value or an exception.

I don't want the former, I don't want the latter, however if they were our only choices I'd choose the latter.

"None of the above". :-)
 As you've said we have other choices:
  - use 'in' and pointers.

Pointers are optional.
 To me that seems contrary to the idea that a basic type is just that  
 basic, eg.
 
 int[char[]] aa;
 int *p;
 int v;
 
 //here we are trying to get the value of "fred" out of the aa without a  
 double lookup.
 p = ("fred" in aa);
 v = *p;
 
 //not too bad I admit, less verbose than
 try {
   v = aa["fred"];
 } catch(Exception e) {
 }

It doesn't work for all types of p, though. e.g. function delegates.
 Ahhh well, I guess all I'm saying is that:
 
 - I dislike the behaviour of v = aa["fred"] when "fred" does not exist, 
 it  seems to be the greater of the evils.

Mother of all evils.
 - I dislike the soln we have to use to avoid a double lookup, but it  
 appears to be the lesser of the evils.

For e.g. hashes of strings and Objects, just returning null is fine And that doesn't require a double lookup either... (except for "in") alias char[] str; str[str] aa; str v = aa["fred"]; --anders
Feb 09 2005
next sibling parent "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 10 Feb 2005 00:19:05 +0100, Anders F Björklund <afb algonet.se>  
wrote:
 Regan Heath wrote:

 But reading a value should not just create and store a blank one.

Sorry if I missled.

<phew>

:)
 You couldn't store "null" in in the old Java 1 class called  
 Hashtable.
 Can't say it was ever a big problem ?

What did it do/return when you requested a non existant element?

It returned null.


Nope, like all collections in Java it can *only* handle Objects. That's why they have all the wrapper object types for primitives: Integer, Byte, Short, Long, Character, Float, Double, etc. And of course the String class is the default, for doing strings (doesn't really matter, since char[] is also an object in Java!) For the JDBC interface, they do a double approach: there is one Object-returning method, and one for each of the primitive types - including a boolean "wasNull" function to check for null values. http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html Quite different. (D does *not* want such wrapper classes/methods)

With that, I agree.
 I fail to see why one wants a dummy new value or an exception.

our only choices I'd choose the latter.

"None of the above". :-)
 As you've said we have other choices:
  - use 'in' and pointers.

Pointers are optional.

Only if you're dealing with an object, or you don't mind the double lookup, right?
 To me that seems contrary to the idea that a basic type is just that   
 basic, eg.
  int[char[]] aa;
 int *p;
 int v;
  //here we are trying to get the value of "fred" out of the aa without  
 a  double lookup.
 p = ("fred" in aa);
 v = *p;
  //not too bad I admit, less verbose than
 try {
   v = aa["fred"];
 } catch(Exception e) {
 }

It doesn't work for all types of p, though. e.g. function delegates.

I suspect this is a bug.
 Ahhh well, I guess all I'm saying is that:
  - I dislike the behaviour of v = aa["fred"] when "fred" does not  
 exist, it  seems to be the greater of the evils.

Mother of all evils.
 - I dislike the soln we have to use to avoid a double lookup, but it   
 appears to be the lesser of the evils.

For e.g. hashes of strings and Objects, just returning null is fine And that doesn't require a double lookup either... (except for "in") alias char[] str; str[str] aa; str v = aa["fred"];

I agree, however when it comes to generics (i.e. templates accepting AA's of both objects and basic types) you're force to use either a pointer or the double lookup. Or you could write 2 versions of the template and specialise one to AA's of basic types. Not sure you can do this? And it seems contrary to the idea of 'generic' :) Regan
Feb 09 2005
prev sibling parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
Anders F Björklund wrote:
 
 It doesn't work for all types of p, though. e.g. function delegates.
 

Are you referring to the thread "Q: how to do AA of delegates keyed by int?"? Because, at least in DMD, it works fine (as I shown in my reply in that thread). _______________________ Carlos Santander Bernal
Feb 09 2005
parent =?ISO-8859-15?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Carlos Santander B. wrote:

 It doesn't work for all types of p, though. e.g. function delegates.

Are you referring to the thread "Q: how to do AA of delegates keyed by int?"? Because, at least in DMD, it works fine (as I shown in my reply in that thread).

The latest DMD version (0.111, 0.112) is not available in GDC just yet. --anders
Feb 09 2005
prev sibling parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
Regan Heath wrote:
 
 As you've said we have other choices:
  - use 'in' and pointers.
 
 To me that seems contrary to the idea that a basic type is just that  
 basic, eg.
 
 int[char[]] aa;
 int *p;
 int v;
 
 //here we are trying to get the value of "fred" out of the aa without a  
 double lookup.
 p = ("fred" in aa);
 v = *p;
 
 //not too bad I admit, less verbose than
 try {
   v = aa["fred"];
 } catch(Exception e) {
 }
 
 Ahhh well, I guess all I'm saying is that:
 
 - I dislike the behaviour of v = aa["fred"] when "fred" does not exist, 
 it  seems to be the greater of the evils.
 
 - I dislike the soln we have to use to avoid a double lookup, but it  
 appears to be the lesser of the evils.

Double lookup isn't necessary, as you have shown before. I'm not sure if I really like the current behavior, but I've adjusted to it, so it doesn't bother me much. Now, if someone can come up with a better idea, that'll be even better. And, IMHO, exceptions are not a better idea. _______________________ Carlos Santander Bernal
Feb 09 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 09 Feb 2005 18:51:53 -0500, Carlos Santander B.  
<csantander619 gmail.com> wrote:
 Regan Heath wrote:
  As you've said we have other choices:
  - use 'in' and pointers.
  To me that seems contrary to the idea that a basic type is just that   
 basic, eg.
  int[char[]] aa;
 int *p;
 int v;
  //here we are trying to get the value of "fred" out of the aa without  
 a  double lookup.
 p = ("fred" in aa);
 v = *p;
  //not too bad I admit, less verbose than
 try {
   v = aa["fred"];
 } catch(Exception e) {
 }
  Ahhh well, I guess all I'm saying is that:
  - I dislike the behaviour of v = aa["fred"] when "fred" does not  
 exist, it  seems to be the greater of the evils.
  - I dislike the soln we have to use to avoid a double lookup, but it   
 appears to be the lesser of the evils.

Double lookup isn't necessary, as you have shown before.

It's either a double lookup or a pointer for basic types.
 I'm not sure if I really like the current behavior, but I've adjusted to  
 it, so it doesn't bother me much. Now, if someone can come up with a  
 better idea, that'll be even better. And, IMHO, exceptions are not a  
 better idea.

I agree. The current method of avoiding a double lookup is the best I've seen/thought of so far, but I still think it's 'yucky'. Regan
Feb 09 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 10 Feb 2005 13:11:10 +1300, Regan Heath <regan netwin.co.nz> wrote:
 On Wed, 09 Feb 2005 18:51:53 -0500, Carlos Santander B.  
 <csantander619 gmail.com> wrote:
 Regan Heath wrote:
  As you've said we have other choices:
  - use 'in' and pointers.
  To me that seems contrary to the idea that a basic type is just that   
 basic, eg.
  int[char[]] aa;
 int *p;
 int v;
  //here we are trying to get the value of "fred" out of the aa without  
 a  double lookup.
 p = ("fred" in aa);
 v = *p;
  //not too bad I admit, less verbose than
 try {
   v = aa["fred"];
 } catch(Exception e) {
 }
  Ahhh well, I guess all I'm saying is that:
  - I dislike the behaviour of v = aa["fred"] when "fred" does not  
 exist, it  seems to be the greater of the evils.
  - I dislike the soln we have to use to avoid a double lookup, but it   
 appears to be the lesser of the evils.

Double lookup isn't necessary, as you have shown before.

It's either a double lookup or a pointer for basic types.
 I'm not sure if I really like the current behavior, but I've adjusted  
 to it, so it doesn't bother me much. Now, if someone can come up with a  
 better idea, that'll be even better. And, IMHO, exceptions are not a  
 better idea.

I agree. The current method of avoiding a double lookup is the best I've seen/thought of so far, but I still think it's 'yucky'.

I guess I _could_ always use a template: # import std.stdio; # # template find(Key, Value) { # bool find(in Value[Key] aa, in Key k, out Value v) { # Value *p = (k in aa); # if (p) v = *p; # return p != null; # } # } # # void main() { # char[][char[]] aa; # char[] v; # # //aa["regan"] = "test"; # if (find!(char[],char[])(aa,"regan",v)) writefln("Found: ",v); # else writefln("Missing"); # } In an ideal world it would look like: if (aa.find("regan",v)) writefln("Found: ",v); else writefln("Missing"); That would take: - some sort of type deduction, to remove the !(char[],char[]) - the feature for arrays that allows: void free_fn(char[] a); to be called: char[] a; a.free_fn(); to also work with a template function as I've used. Regan
Feb 09 2005
prev sibling parent Nick <Nick_member pathlink.com> writes:
In article <opslx7arol23k2f5 ally>, Regan Heath says...
 You couldn't store "null" in in the old Java 1 class called Hashtable.
 Can't say it was ever a big problem ?

What did it do/return when you requested a non existant element?

The Java Hashtable isn't really a good model to follow. It can only store objects, not basic types. To store an integer you would have to use the ugly Integer(3) wrapper class. Nick
Feb 09 2005
prev sibling parent "Ben Hinkle" <bhinkle mathworks.com> writes:
 In the thread above I proposed some helper functions to avoid the double 
 lookup and Ben even wrote some of them.

 bool contains(key_type key, out value_type value);

 --returns existance of value, assigns 'value' if found

 bool contains(key_type key, out index_type at);

 --returns existance of value, assigns 'at' to location which can then be 
 used to get/replace/add an item.

I don't think those tricks work anymore. The implementation of AAs changed around dmd-107 or so and my code broke. I took all that stuff out of my libraries now that "in" returns a pointer.
Feb 08 2005