Jump to page: 1 25  
Page
Thread overview
associative arrays
Jan 07, 2012
RenatoL
Jan 07, 2012
Ali Çehreli
Jan 07, 2012
RenatoL
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
RenatoL
Jan 08, 2012
bearophile
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
Manfred Nowak
Jan 08, 2012
Jesse Phillips
Jan 08, 2012
RenatoL
Jan 09, 2012
dennis luehring
Jan 09, 2012
Manfred Nowak
Jan 10, 2012
dennis luehring
Jan 10, 2012
Manfred Nowak
Jan 08, 2012
Stephen Bennett
Jan 07, 2012
Jonathan M Davis
Jan 08, 2012
Manfred Nowak
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
Kapps
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
Kapps
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
simendsjo
Jan 08, 2012
Manfred Nowak
Jan 08, 2012
simendsjo
Jan 08, 2012
Manfred Nowak
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
simendsjo
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
simendsjo
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
simendsjo
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
simendsjo
Jan 08, 2012
Jonathan M Davis
Jan 08, 2012
simendsjo
Jan 08, 2012
Jonathan M Davis
Jan 09, 2012
Jonathan M Davis
Jan 09, 2012
Andrej Mitrovic
Jan 09, 2012
Andrej Mitrovic
Jan 09, 2012
Andrej Mitrovic
Jan 08, 2012
Manfred Nowak
Jan 08, 2012
Andrej Mitrovic
Jan 09, 2012
Kapps
January 07, 2012
Very quick question

import std.stdio;
void main()
{
	auto arr1 = ["uno":1, "due":2, "tre":3];
	arr1.remove("xxx");
}

also in this case the compiler does not say anything and the program goes out silently ... why? Would not it be better if an exception was raised? After all if i write:

writeln(arr1["xxx"]);

runtime expresses its disappointment...
January 07, 2012
On 01/07/2012 02:11 PM, RenatoL wrote:
> Very quick question
>
> import std.stdio;
> void main()
> {
> 	auto arr1 = ["uno":1, "due":2, "tre":3];
> 	arr1.remove("xxx");
> }
>
> also in this case the compiler does not say anything and the
> program goes out silently ... why? Would not it be better if an
> exception was raised?

I think that could be a valid design choice. On the other hand, since what is required is to remove the element, it is not really an error if the object is already missing. The requirement is met.

> After all if i write:
>
> writeln(arr1["xxx"]);
>
> runtime expresses its disappointment...

You get the exception more simply by this:

    auto e = arr1["xxx"];

But that's understandable because the [] operator is supposed to provide access to a usable object. Since there is no general concept of a null object, there is no object to provide access to, so there is nothing else to do but to throw.

Ali

January 07, 2012
Yes, i agree this may acceptable. On the other hand if i really want/have to remove an item i have to be very careful cause a trivial typo could cause a disaster....
January 07, 2012
On Saturday, January 07, 2012 15:06:30 Ali Çehreli wrote:
> On 01/07/2012 02:11 PM, RenatoL wrote:
>  > Very quick question
>  >
>  > import std.stdio;
>  > void main()
>  > {
>  >
>  > 	auto arr1 = ["uno":1, "due":2, "tre":3];
>  > 	arr1.remove("xxx");
>  >
>  > }
>  >
>  > also in this case the compiler does not say anything and the
>  > program goes out silently ... why? Would not it be better if an
>  > exception was raised?
> 
> I think that could be a valid design choice. On the other hand, since what is required is to remove the element, it is not really an error if the object is already missing. The requirement is met.
> 
>  > After all if i write:
>  >
>  > writeln(arr1["xxx"]);
>  >
>  > runtime expresses its disappointment...
> 
> You get the exception more simply by this:
> 
>      auto e = arr1["xxx"];
> 
> But that's understandable because the [] operator is supposed to provide access to a usable object. Since there is no general concept of a null object, there is no object to provide access to, so there is nothing else to do but to throw.

You likely know this, but I'll point it out in case a newbie to decide to get htrowing behavior out of the substript operator.

If the element is not in the container, then the subscript operator throws a RangeError if -release isn't used, so it's an Error, not an Exception, and isn't a Throwable that you're supposed to catch (since the unwinding of the stack skips destructors, scope statements, finall blocks for any Throwables which aren't either Exception or derived from Exception). Also, without - release, it does no bounds checking and will likely result in a segfault. So, relying on the subscript operator throwing is a _bad_ idea. The idea is that you never give it something that isn't actually in the container.

If you need to check it, and you're dealing with a dynamic or static array, then you check the array's length. If you're dealing with an associative array, then you use the in operator to get a pointer to the element from the container and check whether it's null or not (since if it's null, it wasn't there).

It would probably make remove more expensive if it had to throw when it didn't find an element, and for the most part, it's rather meaningless whether it was in the container before that. As pointed out, remove makes sure that the element is no longer in the container after it's been called. It has no real reason to care whether an element was in there before or not. And if _you_ don't care, then being forced to check whether an element was in the container before trying to remove it would make your code less efficient. The way remove is now, the check only occurs if you do it yourself and therefore actually _want_ it. And odds are, such a check would be an assertion anyway (and therefore would be throwing an AssertError on failure, not an Exception), since the fact that the element wasn't in there anymore is a bug in your code, since your code is assuming that it's there.

So, while I can understand someone's first reaction being why remove doesn't throw if the element isn't there, when you really think through it, it does make more sense for it not to throw.

- Jonathan M Davis
January 08, 2012
On Saturday, January 07, 2012 23:34:05 RenatoL wrote:
> Yes, i agree this may acceptable. On the other hand if i really want/have to remove an item i have to be very careful cause a trivial typo could cause a disaster....

In general, if an element isn't in a container, and you expect it to be there, it's bug in your code and _should_ cause disaster. That is, if your code is assuming that the element must be in the container before you remove it, you should be asserting for that.

assert(key in aa);
aa.remove(key);

This will result in an AssertError if key is not in aa, and upon failure will indicate that you have a bug in your code that you need to fix.

If, on the other hand, it's not a bug if that element is not in the container, then why would your code be assuming that it is? In that case, I don't see why you'd care whether it was actually in the container or not, and having remove not do anything if it isn't there is the perfect behavior in that case.

So, I'd argue that if your code is assuming that the element is in the container, an assertion should be used, and the fact that remove doesn't throw an exception is irrelevant, since it would be the wrong thing to do anyway. And if your code can't assume that the element is in the container already, then just let remove remove it if it's there and do nothing if it's not.

- Jonathan M Davis
January 08, 2012
Jonathan M Davis wrote:

[...]

This sort of explanation is missing in the docs.

-manfred
January 08, 2012
On Sunday, January 08, 2012 00:13:12 Manfred Nowak wrote:
> Jonathan M Davis wrote:
> 
> [...]
> 
> This sort of explanation is missing in the docs.

Which part?

- Jonathan M Davis
January 08, 2012
Yes, Jonathan, you're right.
the question arose precisely from a typo... i had to remove an
item with key "length"... i wrote "lengt" and the item never went
away... i knew that "lengt" was not in my key list... This kind of
mistake is quite tricky, may be using and IDE could help.
January 08, 2012
RenatoL:

> Yes, Jonathan, you're right.
> the question arose precisely from a typo... i had to remove an
> item with key "length"... i wrote "lengt" and the item never went
> away... i knew that "lengt" was not in my key list... This kind of
> mistake is quite tricky, may be using and IDE could help.

This an example that shows that silent failures are sources of bugs... So this time I don't agree with Jonathan Davis.

Python Zen contains:
Errors should never pass silently.

And Python associative arrays show it:

>>> d = {1:2, 3:4}
>>> del d[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 5


The successive rule of the Python Zen says:
Unless explicitly silenced.

Python sets show this at work, they have a 'remove' method that throws if the item is missing, plus a 'discard' method that acts more like D associative arrays, in a sense it's a way to silence explicitly the error:

>>> s = set([1, 2])
>>> s.discard(1)
>>> s
set([2])
>>> s = set([1, 2])
>>> s.discard(3)
>>> s
set([1, 2])
>>> s.remove(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 3

Maybe D associative arrays too should have both kinds of deleting methods :-)

Bye,
bearophile
January 08, 2012
On Saturday, January 07, 2012 21:54:07 bearophile wrote:
> Maybe D associative arrays too should have both kinds of deleting methods :-)

Why? What's the gain? If you care that the element is already in the AA, then do either

assert(key in aa);
aa.remove(key);

or

enforce(key in aa);
aa.remove(key);

I suppose that that's less efficient than remove throwing on failure, since it has to do a double lookup, but since throwing the exception costs _far_ more than that, I don't think that the extra cost really matters

But if you _don't_ care whether the element is in the AA when you remove it, and remove threw when the element wasn't there, then you'd have to do

if(key in aa)
    aa.remove(key);

which would result is a double lookup when you don't want one, and performance _would_ matter, since there isn't necessarily another operation which would cost a lot which is overshadowing the cost of the double lookup (as occurs in the case where you throw the exception when the element isn't there). Also, if you considered the key not being there to be a bug (as seems more likely to me), the fact that remove then threw an assertion would force you to do the extra check _anyway_.

assert(key in aa);
aa.remove(key);

So, as far as I can tell, the current situation is more efficient, and it doesn't cost you any expressiveness. You can still have an exception thrown when remove fails if you use enforce before the call if you want an exception thrown when the element isn't there.

- Jonathan M Davis
« First   ‹ Prev
1 2 3 4 5