www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - associative array behavior

reply novice2 <novice2_member pathlink.com> writes:
Hi.

Associative array automatically add items, if it not existed but was accessed.
Small example:

/**************************/
alias char[] string;

void main()
{
string[string] arr;

if("key" in arr)
printf("key exist\n");
else
printf("key not exist\n");

printf("arr[key]=%.*s\n", arr["key"]);

if("key" in arr)
printf("key exist\n");
else
printf("key not exist\n");
}
/**************************/

For DMD 0.109 this program print:

key not exist
arr[key]=
key exist

Item auto inserted after access to it.
Is it feature or bug?
If it is feature - it is very inconveniently.
So i can't trust to 'in' operator.

Sorry, if a missed something.
Dec 17 2004
next sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"novice2" <novice2_member pathlink.com> wrote in message
news:cput9j$2cu8$1 digitaldaemon.com...
 Hi.

 Associative array automatically add items, if it not existed but was

 Small example:

 /**************************/
 alias char[] string;

 void main()
 {
 string[string] arr;

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");

 printf("arr[key]=%.*s\n", arr["key"]);

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/

 For DMD 0.109 this program print:

 key not exist
 arr[key]=
 key exist

 Item auto inserted after access to it.
 Is it feature or bug?
 If it is feature - it is very inconveniently.
 So i can't trust to 'in' operator.

 Sorry, if a missed something.

This is how it is documented to work. The precedent is C++'s map class. The alternative is to throw an exception and my guess for why it doesn't is that maybe having a function that sometimes throws is slower than always inserting. It does seem a little wierd but it isn't unreasonable. -Ben
Dec 17 2004
next sibling parent reply Martin <Martin_member pathlink.com> writes:
This is a very bad behavior and should be corrected. I know it is a feature, but
a very bad one!

Everything else should work as it is (for example if someone reads an
nonexisting value then a default value is returned.) But reading must not
actually create the element. Reading is reading and writing is writing. If we
don't care that D is a logical, easy to use and easy to understand language,
then why don't we all use Java or something else?

Why spoil the D language?

I truly hope you change it!
(Ok for bakward compatiblity there can be a switch to switch between the on and
another behavior.)


In article <cpuuir$2e66$1 digitaldaemon.com>, Ben Hinkle says...
"novice2" <novice2_member pathlink.com> wrote in message
news:cput9j$2cu8$1 digitaldaemon.com...
 Hi.

 Associative array automatically add items, if it not existed but was

 Small example:

 /**************************/
 alias char[] string;

 void main()
 {
 string[string] arr;

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");

 printf("arr[key]=%.*s\n", arr["key"]);

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/

 For DMD 0.109 this program print:

 key not exist
 arr[key]=
 key exist

 Item auto inserted after access to it.
 Is it feature or bug?
 If it is feature - it is very inconveniently.
 So i can't trust to 'in' operator.

 Sorry, if a missed something.

This is how it is documented to work. The precedent is C++'s map class. The alternative is to throw an exception and my guess for why it doesn't is that maybe having a function that sometimes throws is slower than always inserting. It does seem a little wierd but it isn't unreasonable. -Ben

Dec 17 2004
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Martin wrote:
 This is a very bad behavior and should be corrected. I know it is a 
 feature, but a very bad one!

Do you mean you've weighed up the pros and cons? On practical grounds, not just puristic ones? <snip>
 I truly hope you change it!
 (Ok for bakward compatiblity there can be a switch to switch between 
 the on and another behavior.)

I think D is still planning to be one standardised language, not two subtly different, mutually incompatible languages. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Dec 17 2004
parent reply Juanjo =?iso-8859-1?Q?=C1lvarez?= writes:
On 2004-12-17, Stewart Gordon <smjg_1998 yahoo.com> wrote:
 Martin wrote:
 This is a very bad behavior and should be corrected. I know it is a 
 feature, but a very bad one!


Can you please explain what are the cons of this behavior? I've listened to the "if it can throw an exception it's slower" argument but I don't think that's a good one (against the cons, more difficult to understand, more dificult to debug, unwanted side effects for sure, not logical...)
Dec 18 2004
next sibling parent reply Martin <Martin_member pathlink.com> writes:
My point was, that exeption throwing is NOT nessesary or desirable. For example
if you have a file with words, you count the words and keep the result in an
associative  array. Let's say there was word 'fox' five times. Then array["fox"]
equels 5. But let's say there was no word rabbit. Then array["rabbit"] equals 0.
It's logical. Most of the time 0 means none. Most of the cases when I use
associative arrays are such cases. (Mostly for me, not existing means "" and
that is what it should be).

PROGRAM.CONF:
NAME="My program"
MESSAGE=""
VERSION="1.95"

or

PROGRAM.CONF:
NAME="My program"
VERSION="1.95"

are the same. And my associative array CONF, the element CONF["MESSAGE"] should
be "". Why should I count all the empty strings. 
eg 

PROGRAM.CONF:
NAME="My program"
MESSAGE=""
MESSAGE1=""
MESSAGE2=""
MESSAGE3=""
MESSAGE4=""
MESSAGE5="something"
MESSAGE6=""
MESSAGE7=""
VERSION="1.95"

should be 

PROGRAM.CONF:
NAME="My program"
MESSAGE5="something"
VERSION="1.95"

And when an action occurs in my program, for example the user logs out then I do
printf("%.*s",CONF["MESSAGE5"]);
If this is specified then the user gets the message, if it isn't then  the user
gets nothing. (Ok here I could write the in check, but there are lots of
situations that its very time consuming and makes code much uglyer.)
Most of the time (not given)=(default value). This way I can program much faster
and cleaner.

But sometimes I need to know if the value was actually given or not. Then I use
if("MESSAGE5" in CONF). But now, if I had done printf("%.*s",CONF["MESSAGE5"]);
then everything is spoiled. I need to keep CONF and CONF_original where I do the
'in' clause only in CONF_original, but this is absurd!!!

There is no need that the reading does create the key. There are opIndex and
opIndexAssign. First I thought that maybe it is not possible to read on element
without creating it. It is possible in D. So Walter please change it.

CAN ANYONE TELL ME atleast one good reaseon why the reading of an element should
create it?


If for some reason Walter does not want to change it then I want to create my
own associative arrays. I can use opIndex and opIndexAssign. But tell me, can I
use something to overload 'in' for example if("string" in myArray). And how can
I overload foreach? 

Thanks,

Martin


In article <cq1mtr$1vh1$1 digita ldaemon.com>, Juanjo =?iso-8859-1?Q?=C1lvarez?=
says...
On 2004-12-17, Stewart Gordon <smjg_1998 yahoo.com> wrote:
 Martin wrote:
 This is a very bad behavior and should be corrected. I know it is a 
 feature, but a very bad one!


Can you please explain what are the cons of this behavior? I've listened to the "if it can throw an exception it's slower" argument but I don't think that's a good one (against the cons, more difficult to understand, more dificult to debug, unwanted side effects for sure, not logical...)

Dec 18 2004
parent reply MMM <MMM_member pathlink.com> writes:
The question was: is it possible to owerload the 'in' operator and the foreach
one?

Does anybody know?

Thanks!

In article <cq2etq$2m9v$1 digitaldaemon.com>, Martin says...
My point was, that exeption throwing is NOT nessesary or desirable. For example
if you have a file with words, you count the words and keep the result in an
associative  array. Let's say there was word 'fox' five times. Then array["fox"]
equels 5. But let's say there was no word rabbit. Then array["rabbit"] equals 0.
It's logical. Most of the time 0 means none. Most of the cases when I use
associative arrays are such cases. (Mostly for me, not existing means "" and
that is what it should be).

PROGRAM.CONF:
NAME="My program"
MESSAGE=""
VERSION="1.95"

or

PROGRAM.CONF:
NAME="My program"
VERSION="1.95"

are the same. And my associative array CONF, the element CONF["MESSAGE"] should
be "". Why should I count all the empty strings. 
eg 

PROGRAM.CONF:
NAME="My program"
MESSAGE=""
MESSAGE1=""
MESSAGE2=""
MESSAGE3=""
MESSAGE4=""
MESSAGE5="something"
MESSAGE6=""
MESSAGE7=""
VERSION="1.95"

should be 

PROGRAM.CONF:
NAME="My program"
MESSAGE5="something"
VERSION="1.95"

And when an action occurs in my program, for example the user logs out then I do
printf("%.*s",CONF["MESSAGE5"]);
If this is specified then the user gets the message, if it isn't then  the user
gets nothing. (Ok here I could write the in check, but there are lots of
situations that its very time consuming and makes code much uglyer.)
Most of the time (not given)=(default value). This way I can program much faster
and cleaner.

But sometimes I need to know if the value was actually given or not. Then I use
if("MESSAGE5" in CONF). But now, if I had done printf("%.*s",CONF["MESSAGE5"]);
then everything is spoiled. I need to keep CONF and CONF_original where I do the
'in' clause only in CONF_original, but this is absurd!!!

There is no need that the reading does create the key. There are opIndex and
opIndexAssign. First I thought that maybe it is not possible to read on element
without creating it. It is possible in D. So Walter please change it.

CAN ANYONE TELL ME atleast one good reaseon why the reading of an element should
create it?


If for some reason Walter does not want to change it then I want to create my
own associative arrays. I can use opIndex and opIndexAssign. But tell me, can I
use something to overload 'in' for example if("string" in myArray). And how can
I overload foreach? 

Thanks,

Martin


In article <cq1mtr$1vh1$1 digita ldaemon.com>, Juanjo =?iso-8859-1?Q?=C1lvarez?=
says...
On 2004-12-17, Stewart Gordon <smjg_1998 yahoo.com> wrote:
 Martin wrote:
 This is a very bad behavior and should be corrected. I know it is a 
 feature, but a very bad one!


Can you please explain what are the cons of this behavior? I've listened to the "if it can throw an exception it's slower" argument but I don't think that's a good one (against the cons, more difficult to understand, more dificult to debug, unwanted side effects for sure, not logical...)


Dec 19 2004
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
MMM wrote:
 The question was: is it possible to owerload the 'in' operator and the foreach
 one?

in - not yet foreach - look up opApply in the docs. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Dec 20 2004
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Juanjo ┴lvarez wrote:
 On 2004-12-17, Stewart Gordon <smjg_1998 yahoo.com> wrote:
 
Martin wrote:

This is a very bad behavior and should be corrected. I know it is a 
feature, but a very bad one!


Can you please explain what are the cons of this behavior?

Basically, that it takes an extra step to check whether an element is in before looking it up.
 I've listened to the "if it can throw an exception it's slower" argument but I
don't
 think that's a good one (against the cons, more difficult to understand,
 more dificult to debug, unwanted side effects for sure, not logical...)

One could debate whether looking up a non-existent AA key is an expected or unexpected condition. But the current behaviour has its strengths: - it works well in cases where no element is ever set to ValueType.init or can be considered equivalent to a non-existent element - it makes it easy to do a sparse matrix Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Dec 20 2004
parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Stewart Gordon wrote:

 This is a very bad behavior and should be corrected. I know it is a 
 feature, but a very bad one!


Can you please explain what are the cons of this behavior?

Basically, that it takes an extra step to check whether an element is in before looking it up.

The very bad behaviour is *not* that it returns an empty value. (that has it strengths, as you and others have pointed out...) It's that it modifies the AA, when you just try to read a value ? --anders
Dec 20 2004
prev sibling next sibling parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Ben Hinkle wrote:

 This is how it is documented to work. The precedent is C++'s map class. The
 alternative is to throw an exception and my guess for why it doesn't is that
 maybe having a function that sometimes throws is slower than always
 inserting. It does seem a little wierd but it isn't unreasonable.

Where is this documented, by the way ? (Couldn't find it on the page about Associative Arrays: http://www.digitalmars.com/d/arrays.html#associative ?) I guess the default initializer is used for clearing the entry that one tries to access ? (When I tested, it set the values of strings to "" and integers to 0) Too bad that "in" still returns bit, on DMD 0.102 (GDC). --anders
Dec 17 2004
parent "Ben Hinkle" <bhinkle mathworks.com> writes:
"Anders F Bj÷rklund" <afb algonet.se> wrote in message
news:cpv4vd$2ll9$1 digitaldaemon.com...
 Ben Hinkle wrote:

 This is how it is documented to work. The precedent is C++'s map class.


 alternative is to throw an exception and my guess for why it doesn't is


 maybe having a function that sometimes throws is slower than always
 inserting. It does seem a little wierd but it isn't unreasonable.

Where is this documented, by the way ? (Couldn't find it on the page about Associative Arrays: http://www.digitalmars.com/d/arrays.html#associative ?)

Hmm. I guess I was mistaken. I can't find it either. sorry about that!
 I guess the default initializer is used for clearing
 the entry that one tries to access ? (When I tested,
 it set the values of strings to "" and integers to 0)

 Too bad that "in" still returns bit, on DMD 0.102 (GDC).

 --anders

Dec 17 2004
prev sibling next sibling parent reply novice2 <novice2_member pathlink.com> writes:
IMHO access to not existing items in associative array should throw exception
"Out of bounds", like to access to not existing items in normal arrays.
IMHO auto creating not existing items is confuse. It is bad side effect.

For me disabling autocreating will have no pros (?) and some cons (better error
detection).

good luck
novice2.

In article <cpuuir$2e66$1 digitaldaemon.com>, Ben Hinkle says...
"novice2" <novice2_member pathlink.com> wrote in message
news:cput9j$2cu8$1 digitaldaemon.com...
 Hi.

 Associative array automatically add items, if it not existed but was

 Small example:

 /**************************/
 alias char[] string;

 void main()
 {
 string[string] arr;

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");

 printf("arr[key]=%.*s\n", arr["key"]);

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/

 For DMD 0.109 this program print:

 key not exist
 arr[key]=
 key exist

 Item auto inserted after access to it.
 Is it feature or bug?
 If it is feature - it is very inconveniently.
 So i can't trust to 'in' operator.

 Sorry, if a missed something.

This is how it is documented to work. The precedent is C++'s map class. The alternative is to throw an exception and my guess for why it doesn't is that maybe having a function that sometimes throws is slower than always inserting. It does seem a little wierd but it isn't unreasonable. -Ben

Dec 18 2004
parent reply Martin <Martin_member pathlink.com> writes:
It is very convinient that assosiative array returns a default value when a
non-existing key is adressed.
I mainly use char [][char[]]  type arrays. Most time it is only the value that
it is interesting and it is very good that  (not set)=""
When I really whant to know if the value is not set or set to "" then I use the
in clause. But now reading spoils it.

I THINK THAT READING MUST NOT CREATE A NEW KEY.
READING IS READING WRITING IS WRITING.

My suggestion is that reading should still return a default value but writing
should not create the new key!
What do you think?




In article <cq1343$1duk$1 digitaldaemon.com>, novice2 says...
IMHO access to not existing items in associative array should throw exception
"Out of bounds", like to access to not existing items in normal arrays.
IMHO auto creating not existing items is confuse. It is bad side effect.

For me disabling autocreating will have no pros (?) and some cons (better error
detection).

good luck
novice2.

In article <cpuuir$2e66$1 digitaldaemon.com>, Ben Hinkle says...
"novice2" <novice2_member pathlink.com> wrote in message
news:cput9j$2cu8$1 digitaldaemon.com...
 Hi.

 Associative array automatically add items, if it not existed but was

 Small example:

 /**************************/
 alias char[] string;

 void main()
 {
 string[string] arr;

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");

 printf("arr[key]=%.*s\n", arr["key"]);

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/

 For DMD 0.109 this program print:

 key not exist
 arr[key]=
 key exist

 Item auto inserted after access to it.
 Is it feature or bug?
 If it is feature - it is very inconveniently.
 So i can't trust to 'in' operator.

 Sorry, if a missed something.

This is how it is documented to work. The precedent is C++'s map class. The alternative is to throw an exception and my guess for why it doesn't is that maybe having a function that sometimes throws is slower than always inserting. It does seem a little wierd but it isn't unreasonable. -Ben


Dec 18 2004
parent novice2 <novice2_member pathlink.com> writes:
My suggestion is that reading should still return a default value but writing
should not create the new key!

Yes. I will be good, IMHO. I use char[char[]] too, and after first debug printf i loose information about was originally key exist or it was autoinserted.
What do you think?

IMHO autoinserting should be disabled. About result of read non existed key: for me, any of two variants appropriate: return default value or throw exception.
Dec 18 2004
prev sibling parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Ben Hinkle wrote:

Associative array automatically add items,
if it not existed but was accessed.

This is how it is documented to work. The precedent is C++'s map class. The alternative is to throw an exception and my guess for why it doesn't is that maybe having a function that sometimes throws is slower than always inserting. It does seem a little wierd but it isn't unreasonable.

It just looks like a bug in the D compiler ?
 import std.stdio;
 void main()
 {
   char[][char[]] hash;
 
   hash["this"];
   hash["looks"];
   hash["like"];
   hash["a"];
   hash["bug"];
 
   foreach(char[] str; hash.keys)
     writefln(str);
 }

I don't think that it should output anything ? Surely it is not intended that I need to write:
 ("key" in hash ? hash["key"] : "")

just to avoid accidently setting it when reading ? I'm fine with it *returning* a zero/null value. Since arrays are always being initialized with the default initializer, it actually makes sense. Just don't think that it should be *adding* one ? Like someone suggested, maybe it should be treated as out of bounds ? Throw exceptions in -debug mode ? (just as with the regular indexed arrays, that is: ArrayBoundsError exceptions being thrown at runtime) --anders
Dec 18 2004
parent reply Think <Think_member pathlink.com> writes:
Like someone suggested, maybe it should be treated
as out of bounds ? Throw exceptions in -debug mode ?

Yes but there should be a different switch for it. In most of my programs I relay on returning a default value, if element does not exist. But some people may need to test their programs so this option would be needed. But this option sholdn't be default or else I still have to write ("key" in hash ? hash["key"] : "") just for avoining the exception. In article <cq2h5u$2n99$1 digitaldaemon.com>, =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
Ben Hinkle wrote:

Associative array automatically add items,
if it not existed but was accessed.

This is how it is documented to work. The precedent is C++'s map class. The alternative is to throw an exception and my guess for why it doesn't is that maybe having a function that sometimes throws is slower than always inserting. It does seem a little wierd but it isn't unreasonable.

It just looks like a bug in the D compiler ?
 import std.stdio;
 void main()
 {
   char[][char[]] hash;
 
   hash["this"];
   hash["looks"];
   hash["like"];
   hash["a"];
   hash["bug"];
 
   foreach(char[] str; hash.keys)
     writefln(str);
 }

I don't think that it should output anything ? Surely it is not intended that I need to write:
 ("key" in hash ? hash["key"] : "")

just to avoid accidently setting it when reading ? I'm fine with it *returning* a zero/null value. Since arrays are always being initialized with the default initializer, it actually makes sense. Just don't think that it should be *adding* one ? Like someone suggested, maybe it should be treated as out of bounds ? Throw exceptions in -debug mode ? (just as with the regular indexed arrays, that is: ArrayBoundsError exceptions being thrown at runtime) --anders

Dec 19 2004
parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Think wrote:

Like someone suggested, maybe it should be treated
as out of bounds ? Throw exceptions in -debug mode ?

Yes but there should be a different switch for it. In most of my programs I relay on returning a default value, if element does not exist. But some people may need to test their programs so this option would be needed. But this option sholdn't be default or else I still have to write ("key" in hash ? hash["key"] : "") just for avoining the exception.

On second thought, it should probably *not* throw exceptions. An associative array doesn't really have any bounds per se... Languages like Perl don't need to separate between the two, since e.g. 0 and undef are different. But in D it's 0 and 0, (*) so you still need "in" to check if it really was set to zero... (in case you care about it, most programs wouldn't I suppose ?) But having it throw exceptions is probably just as annoying as having it write things to the A.A. when just reading, I agree. --anders *. For int[type] dictionaries, that is. (any non-reference AA)
Dec 19 2004
prev sibling next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
This is, unfortunately, how the thing is designed to work.

Look at
	<expr> in <assoc_array>
which returns null if the element doesn't exist, and a pointer to the 
element otherwise.

novice2 wrote:
 Hi.
 
 Associative array automatically add items, if it not existed but was accessed.
 Small example:
 
 /**************************/
 alias char[] string;
 
 void main()
 {
 string[string] arr;
 
 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 
 printf("arr[key]=%.*s\n", arr["key"]);
 
 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/
 
 For DMD 0.109 this program print:
 
 key not exist
 arr[key]=
 key exist
 
 Item auto inserted after access to it.
 Is it feature or bug?
 If it is feature - it is very inconveniently.
 So i can't trust to 'in' operator.
 
 Sorry, if a missed something.
 
 

Dec 17 2004
parent reply "Garett Bass" <gtbass studiotekne.com> writes:
Based on the implementation of Java's Map, it seems more 
reasonable to me that arr["key"] should return null in the 
printf() example provided.  How can reading the value create 
a value, and what value is created?

After the printf(), does arr["key"] == null?  This sure 
looks like a bug to me.


 alias char[] string;

 void main()
 {
 string[string] arr;

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");

 printf("arr[key]=%.*s\n", arr["key"]);

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/

 For DMD 0.109 this program print:

 key not exist
 arr[key]=
 key exist


Dec 17 2004
parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Garett Bass wrote:

 Based on the implementation of Java's Map, it seems more 
 reasonable to me that arr["key"] should return null in the 
 printf() example provided.  How can reading the value create 
 a value, and what value is created?

Reading the value creates the default initialized value... i.e. "" for strings and 0 for integers (see the type list)
 After the printf(), does arr["key"] == null?  This sure 
 looks like a bug to me.

Both in the printf and afterwards, the key becomes set. Only ("key" in arr) checks it, without modifying it too. I also think it's a bug. (it should return null, not set it!) --anders
Dec 18 2004
prev sibling next sibling parent "Regan Heath" <regan netwin.co.nz> writes:
On Fri, 17 Dec 2004 15:17:07 +0000 (UTC), novice2  
<novice2_member pathlink.com> wrote:
 Hi.

 Associative array automatically add items, if it not existed but was  
 accessed.
 Small example:

 /**************************/
 alias char[] string;

 void main()
 {
 string[string] arr;

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");

 printf("arr[key]=%.*s\n", arr["key"]);

 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/

 For DMD 0.109 this program print:

 key not exist
 arr[key]=
 key exist

 Item auto inserted after access to it.
 Is it feature or bug?
 If it is feature - it is very inconveniently.
 So i can't trust to 'in' operator.

 Sorry, if a missed something.

You can do this: item = "foo" in arr; Regan
Dec 19 2004
prev sibling parent reply Paul Bonser <misterpib gmail.com> writes:
How about an isset() function, like in PHP? To check if there is a key 
set. Something like:

if (myArray.isset("key"))
	...

Just an idea.

-PIB

novice2 wrote:
 Hi.
 
 Associative array automatically add items, if it not existed but was accessed.
 Small example:
 
 /**************************/
 alias char[] string;
 
 void main()
 {
 string[string] arr;
 
 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 
 printf("arr[key]=%.*s\n", arr["key"]);
 
 if("key" in arr)
 printf("key exist\n");
 else
 printf("key not exist\n");
 }
 /**************************/
 
 For DMD 0.109 this program print:
 
 key not exist
 arr[key]=
 key exist
 
 Item auto inserted after access to it.
 Is it feature or bug?
 If it is feature - it is very inconveniently.
 So i can't trust to 'in' operator.
 
 Sorry, if a missed something.
 
 

Jan 15 2005
parent reply Chris Sauls <Chris_member pathlink.com> writes:
In article <cscvje$10aa$1 digitaldaemon.com>, Paul Bonser says...
How about an isset() function, like in PHP? To check if there is a key 
set. Something like:

if (myArray.isset("key"))
	...

The following works currently: # # if (("key" in myArray) == null) # -- Chris S
Jan 16 2005
parent reply Paul Bonser <misterpib gmail.com> writes:
Chris Sauls wrote:
 In article <cscvje$10aa$1 digitaldaemon.com>, Paul Bonser says...
 
How about an isset() function, like in PHP? To check if there is a key 
set. Something like:

if (myArray.isset("key"))
	...

The following works currently: # # if (("key" in myArray) == null) # -- Chris S

And that doesn't add an empty item named "key"? -PIB
Jan 16 2005
next sibling parent reply Carotinho <carotinobg yahoo.it> writes:
Hi!

Paul Bonser wrote:
 And that doesn't add an empty item named "key"?
 
 -PIB

Yes, there was a thread about this behaviour, but I think it's been fixed with latest version. I'm going to verify. Carotinho
Jan 16 2005
parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Carotinho wrote:

And that doesn't add an empty item named "key"?

Yes, there was a thread about this behaviour, but I think it's been fixed with latest version. I'm going to verify.

The thread was about the fact that: if (myArray("key")) *will* add a new item (default init) for the "key" key. The change in DMD 0.107 was that: ("key" in myArray) now returns a pointer, instead of the old true/false: http://www.digitalmars.com/d/changelog.html#new0107 Since there is no difference in D between null and false, the following code should still work: if ("key" in myArray) But reading the key means "or create it if it doesn't exist" This could have been mentioned more, in the documentation: http://www.digitalmars.com/d/arrays.html#associative --anders
Jan 16 2005
prev sibling next sibling parent David L. Davis <SpottedTiger yahoo.com> writes:
In article <csek55$2kef$1 digitaldaemon.com>, Paul Bonser says...
Chris Sauls wrote:
 In article <cscvje$10aa$1 digitaldaemon.com>, Paul Bonser says...
 
How about an isset() function, like in PHP? To check if there is a key 
set. Something like:

if (myArray.isset("key"))
	...

The following works currently: # # if (("key" in myArray) == null) # -- Chris S

And that doesn't add an empty item named "key"? -PIB

Paul Bonser: Just this weekend I was looking into how associative array work, and have discovered a few things that I'd like to share by modifying your code example a bit. Hopefully you will find it helpful. I created a few free functions to do the main work in your example, but really a "class" would be better suited to encapsulate your associative array with these functions, tis a lot more reuseable. :) Just remove the "#"s to use: # private import std.stdio; # # alias char[] string; # # void main() # { # string[ string ] arr; # # // before adding "key" # writefln( "\"key\" exist = %s", # ( isset( arr, "key" ) ? "true" : "false" ) ); # writefln(); # # writefln( "adding \"key\" and \"key2\"" ); # arr[ "key" ] = "added a key"; # arr[ "key2" ] = "added another key"; # writefln( "number of entries in arr = %d", arr.length ); # displayEntries( arr ); # # // after adding keys # writefln( "\"key\" exist = %s", # ( isset( arr, "key" ) ? "true" : "false" ) ); # writefln(); # # writefln( "removing key2..." ); # remove( arr, "key2" ); # displayEntries( arr ); # } # # bool isset( in string[ string ] arr, in char[] sKey ) # { # if ( ( sKey in arr ) != null ) # return true; # else # return false; # } # # void remove( inout string[ string ] arr, in char[] sKey ) # { # delete arr[ sKey ]; # } # # void removeall( inout string[ string ] arr ) # { # foreach( char[] sKey; arr.keys ) # delete arr[ sKey ]; # } # # void displayEntries( in string[ string ] arr ) # { # foreach( char[] sKey, char[] sValue; arr ) # writefln( "sKey=\"%s\", sValue=\"%s\"", sKey, sValue ); # } output: C:\dmd>bin\dmd assocarray.d C:\dmd\bin\..\..\dm\bin\link.exe assocarray,,,user32+kernel32/noi; C:\dmd>assocarray "key" exist = false adding "key" and "key2" number of entries in arr = 2 sKey="key", sValue="added a key" sKey="key2", sValue="added another key" "key" exist = true removing key2... sKey="key", sValue="added a key" C:\dmd> ------------------------ David L. ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!"
Jan 16 2005
prev sibling parent reply Chris Sauls <Chris_member pathlink.com> writes:
In article <csek55$2kef$1 digitaldaemon.com>, Paul Bonser says...
Chris Sauls wrote:
 In article <cscvje$10aa$1 digitaldaemon.com>, Paul Bonser says...
 
How about an isset() function, like in PHP? To check if there is a key 
set. Something like:

if (myArray.isset("key"))
	...

The following works currently: # # if (("key" in myArray) == null) # -- Chris S

And that doesn't add an empty item named "key"? -PIB

No it sure doesn't. To check for certain I tossed together this little test. Compiled and ran with DMD 0.110 and found that in-expressions do /not/ add empty items. -- Chris Sauls module aatest; import std.stdio; void main() { char[][char[]] map; char[]* value; writefln("\nStart"); writefln("map.length == ", map.length); value = "foo" in map; writefln("\nUsing 'in' the first time"); writefln("foo in map == ", value == null ? "null" : *value); writefln("map.length == ", map.length); map["foo"] = "abc"; value = "foo" in map; writefln("\nAdding item, using 'in' the second time"); writefln("foo in map == ", value == null ? "null" : *value); writefln("map.length == ", map.length); delete map["foo"]; value = "foo" in map; writefln("\nDeleting item, using 'in' the third time"); writefln("foo in map == ", value == null ? "null" : *value); writefln("map.length == ", map.length); }
Jan 17 2005
next sibling parent Paul Bonser <misterpib gmail.com> writes:
 No it sure doesn't.  To check for certain I tossed together this little test.
 Compiled and ran with DMD 0.110 and found that in-expressions do /not/ add
empty
 items.
 
 -- Chris Sauls

Well then, I retract my confused suggestion and am now happy. :) See, that smiley means I'm happy! -PIB
Jan 17 2005
prev sibling parent reply Kris <Kris_member pathlink.com> writes:
The issue was never about 'in' ... it was about the read-only semantics of

foo = myAA ['key'];
if (foo)
..

which actually modifies the 'myAA' with an empty key, if the entry did not exist
prior to the read operation. Of course, this means that your code will break the
next time this key is used (since there's now a bogus entry present).

Question: if you performed a read operation on any other kind of array, would
you expect the content to be modified? If you read from a file, would you expect
the file-length the change? To say that this AA behavior departs from convention
would be something of an understatement.

It used to be that two hash-table lookups were needed to retrieve an entry, when
one wished to avoid this bizzare and contrary behavior. Recently, Walter removed
the necessity for the two lookups ...

I'd call that a band-aid on a kludge. But that's just my opinion. Yes, it is
nice having AA as part of the language core. Yes, it is convenient to avoid a
cast from Object to the class type contained. Yes, there is some value in having
a single AA container for both classes and native types. The price for this, in
Walter's apparent view, is to break one of the most fundamental rules regarding
read-only behavior (using AA purely as an rValue, treats it like an lValue
also). I'd say that's a rather high price to pay -- I mean, it's only an
associative array -- not the failover system for a nuclear reactor ... why
introduce, in the core language, such a sneaky mechanism to break seemingly
valid code?

digitalmars.D.dtl/124


In article <csfsgn$q3s$1 digitaldaemon.com>, Chris Sauls says...
In article <csek55$2kef$1 digitaldaemon.com>, Paul Bonser says...
Chris Sauls wrote:
 In article <cscvje$10aa$1 digitaldaemon.com>, Paul Bonser says...
 
How about an isset() function, like in PHP? To check if there is a key 
set. Something like:

if (myArray.isset("key"))
	...

The following works currently: # # if (("key" in myArray) == null) # -- Chris S

And that doesn't add an empty item named "key"? -PIB

No it sure doesn't. To check for certain I tossed together this little test. Compiled and ran with DMD 0.110 and found that in-expressions do /not/ add empty items. -- Chris Sauls module aatest; import std.stdio; void main() { char[][char[]] map; char[]* value; writefln("\nStart"); writefln("map.length == ", map.length); value = "foo" in map; writefln("\nUsing 'in' the first time"); writefln("foo in map == ", value == null ? "null" : *value); writefln("map.length == ", map.length); map["foo"] = "abc"; value = "foo" in map; writefln("\nAdding item, using 'in' the second time"); writefln("foo in map == ", value == null ? "null" : *value); writefln("map.length == ", map.length); delete map["foo"]; value = "foo" in map; writefln("\nDeleting item, using 'in' the third time"); writefln("foo in map == ", value == null ? "null" : *value); writefln("map.length == ", map.length); }

Jan 17 2005
next sibling parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Kris wrote:

 Question: if you performed a read operation on any other kind of array, would
 you expect the content to be modified? If you read from a file, would you
expect
 the file-length the change? To say that this AA behavior departs from
convention
 would be something of an understatement.

Hopefully, the current behaviour is a bug that will eventually be fixed and not a broken design? (not that it really matters in the meantime...) Unfortunately, it seems to work as intended:
 /*************************************************
  * Get pointer to value in associative array indexed by key.
  * Add entry for key if it is not already there.
  */
 
 void *_aaGet(aaA*[] *aa, TypeInfo keyti, int valuesize, ...)

versus
 /*************************************************
  * Determine if key is in aa.
  * Returns:
  *	null	not in aa
  *	!=null	in aa, return pointer to value
  */
 
 void* _aaIn(aaA*[] aa, TypeInfo keyti, ...)

Which means that currently you must use "in" with associative arrays, just as you must use "is" when comparing object pointers for identity. I still don't get *why* it's a good idea to create it, if it is missing? --anders
Jan 17 2005
prev sibling parent Patrick Down <Patrick_member pathlink.com> writes:
Ruby does something with it hash types that I think is good.
The constructor of the hash takes a function that provides
the default behaviour when a key is not found.  Associative
arrays in D do not have constructors but it could be an
attribute.

// throw exception
int[char[]] theMap;
theMap.onKeyNotFound = 
delegate(int[char[]] map, char[] key) { throw KeyNotFoundError(); }

// return default value
int[char[]] theMap;
theMap.onKeyNotFound = 
delegate(int[char[]] map, char[] key) { return 0; }

// Add it to the assoc array
int[char[]] theMap;
theMap.onKeyNotFound = 
delegate(int[char[]] map, char[] key) { map[key] = 0; return 0; }
Jan 17 2005