digitalmars.D - AA default value?
- Janice Caron (27/27) Jan 25 2008 The big problem for me with associative arrays is that I often have to
- Jarrett Billingsley (21/25) Jan 25 2008 What's funny is that a while ago ((long) before 1.0), if you looked up a...
- Oskar Linde (23/56) Jan 25 2008 I believe the implemented solution to the old problem overshoot the best...
- Sean Kelly (4/30) Jan 25 2008 Agreed. And I think this was brought up at the time, but it wasn't
- Jason House (3/10) Jan 25 2008 That solution is assuming a specific answer to the question of "should i...
- Janice Caron (9/11) Jan 25 2008 Yeah! I'll second that.
- Jason House (4/21) Jan 25 2008 I'd be content with (lazy) syntax above. Two gotchas:
- Ary Borenszweig (3/9) Jan 25 2008 But then you can't tell wheter the key was present and the value was
- Janice Caron (18/27) Jan 25 2008 If knowing that is important, you must use "in", as you always have
- Leandro Lucarella (13/40) Jan 25 2008 aa.get(key, defaultvalue) (a la python)?
- Janice Caron (5/7) Jan 25 2008 I'm not proposing a syntax, I'm proposing an idea. I don't care about
- Janice Caron (7/8) Jan 25 2008 Spot the deliberate (ahem) mistake! Hint - there's a missing
- Bill Baxter (34/44) Jan 25 2008 Oskar gave you a solution.
- Janice Caron (3/7) Jan 25 2008 Typo. I meant
- Jason House (2/11) Jan 25 2008 If the behavior is defined at the location of the index call, I'd be ver...
The big problem for me with associative arrays is that I often have to write ugly code like: auto p = key in aa; if (p) { auto val = *p; } else { /* whatever */ } instead of merely auto val = aa[key]; In order to avoid superfluous lookups, the code that I actually end up writing doesn't use the square brackets at all, which kind of defeats the object of the built-in array-like syntax. What would seriously make for nicely readable code would be if the behavior of aa[key] could be changed. Currently, aa[key] throws an exception (in Debug mode) or falls over (in Release mode) if key does not exist. Wouldn't it be nicer if, instead, it simply returned typeof(aa[key]).init if the key was not present in the array? Or perhaps an even more exotic syntax like auto val = aa[key; defaultValue]; might work. (None of this would preclude people from using "in" if they explicitly wanted to check).
Jan 25 2008
"Janice Caron" <caron800 googlemail.com> wrote in message news:mailman.24.1201263099.5260.digitalmars-d puremagic.com...Wouldn't it be nicer if, instead, it simply returned typeof(aa[key]).init if the key was not present in the array?What's funny is that a while ago ((long) before 1.0), if you looked up a key in an AA and the key didn't exist, it'd be added with a value of typeof(aa[key]).init. So int[int] aa; writefln(aa[5]); would give "0" as the output. This was to mirror the behavior of C++'s std::map but many people opposed it, so now we have what we have now.. The issue is that you can't cover all the bases with a single type. Some people want the auto-insertion, some don't. Some want it to disallow updates, i.e. allow a key-value pair to be inserted but never modified. Some want the opposite, where you have to explicitly use an insert method to insert the values, but once they're in, they can be modified as much as you like. At least the nice thing about the AAs is that they're simple to build custom containers on top of them, so most/all of these things can be implemented as structs wrapping them. The downside is that with the current set of operator overloads and features, you can never make a custom type that can replace the builtin one in all cases.
Jan 25 2008
Jarrett Billingsley wrote:"Janice Caron" <caron800 googlemail.com> wrote in message news:mailman.24.1201263099.5260.digitalmars-d puremagic.com...I believe the implemented solution to the old problem overshoot the best solution, which would have been to make a rvalue expression aa[5] return 0, but *without* inserting 5 into the aa. I have for ages had the following two simple utility functions in most code I write that uses AAs: T get(T,U)(T[U] aa, U key) { T* ptr = key in aa; if (ptr) return *ptr; return T.init; } T get(T,U,int dummy=1)(T[U] aa, U key, lazy T defaultValue) { T* ptr = key in aa; if (ptr) return *ptr; return defaultValue; } and almost always use aa.get(5), instead of aa[5].Wouldn't it be nicer if, instead, it simply returned typeof(aa[key]).init if the key was not present in the array?What's funny is that a while ago ((long) before 1.0), if you looked up a key in an AA and the key didn't exist, it'd be added with a value of typeof(aa[key]).init. So int[int] aa; writefln(aa[5]); would give "0" as the output. This was to mirror the behavior of C++'s std::map but many people opposed it, so now we have what we have now..The issue is that you can't cover all the bases with a single type. Some people want the auto-insertion, some don't. Some want it to disallow updates, i.e. allow a key-value pair to be inserted but never modified. Some want the opposite, where you have to explicitly use an insert method to insert the values, but once they're in, they can be modified as much as you like. At least the nice thing about the AAs is that they're simple to build custom containers on top of them, so most/all of these things can be implemented as structs wrapping them. The downside is that with the current set of operator overloads and features, you can never make a custom type that can replace the builtin one in all cases.The biggest problem with custom containers is the lack of a reference return type. -- Oskar
Jan 25 2008
Oskar Linde wrote:Jarrett Billingsley wrote:Agreed. And I think this was brought up at the time, but it wasn't implemented for some reason. Sean"Janice Caron" <caron800 googlemail.com> wrote in message news:mailman.24.1201263099.5260.digitalmars-d puremagic.com...I believe the implemented solution to the old problem overshoot the best solution, which would have been to make a rvalue expression aa[5] return 0, but *without* inserting 5 into the aa.Wouldn't it be nicer if, instead, it simply returned typeof(aa[key]).init if the key was not present in the array?What's funny is that a while ago ((long) before 1.0), if you looked up a key in an AA and the key didn't exist, it'd be added with a value of typeof(aa[key]).init. So int[int] aa; writefln(aa[5]); would give "0" as the output. This was to mirror the behavior of C++'s std::map but many people opposed it, so now we have what we have now..
Jan 25 2008
Sean Kelly Wrote:Oskar Linde wrote:That solution is assuming a specific answer to the question of "should indexing a non-existent entry be an error?". Sometimes, I write code that assumes stuff will be pre-existing in an AA / STL map. When this is the case, I prefer the D behavior. When code works better with defaults, it's annoying. I'd really prefer to have a choice. Additionally, AA's of classes that return null for unused indexes isn't particularly helpful. Returning a non-duped default object is usually worse than returning null. To me, there seems to be enough variation in what people would want that some kind of policy (template paramter, included function object, etc...) would be better.I believe the implemented solution to the old problem overshoot the best solution, which would have been to make a rvalue expression aa[5] return 0, but *without* inserting 5 into the aa.Agreed. And I think this was brought up at the time, but it wasn't implemented for some reason.
Jan 25 2008
On 1/25/08, Jason House <jason.james.house gmail.com> wrote:I'd really prefer to have a choice.Yeah! I'll second that. Not sure how it would work though. Maybe something like: int[int] aa; auto x = aa[5]; // run-time error aa.default = 0; auto y = aa[5]; // y = 0;Additionally, AA's of classes that return null for unused indexes isn't particularly helpful. Returning a non-duped default object is usually worse than returning null. To me, there seems to be enough variation in what people would want that some kind of policy (template paramter, included function object, etc...) would be better.Sounds good to me. Maybe the .default property could be lazy (so it could call new when needed)?
Jan 25 2008
Janice Caron Wrote:On 1/25/08, Jason House <jason.james.house gmail.com> wrote:I'd be content with (lazy) syntax above. Two gotchas: * The default keyword (used in switches) may block that property * New AA's are null and property access would fail. Of course, I'd like to see that changed anyway.I'd really prefer to have a choice.Yeah! I'll second that. Not sure how it would work though. Maybe something like: int[int] aa; auto x = aa[5]; // run-time error aa.default = 0; auto y = aa[5]; // y = 0;Additionally, AA's of classes that return null for unused indexes isn't particularly helpful. Returning a non-duped default object is usually worse than returning null. To me, there seems to be enough variation in what people would want that some kind of policy (template paramter, included function object, etc...) would be better.Sounds good to me. Maybe the .default property could be lazy (so it could call new when needed)?
Jan 25 2008
Janice Caron wrote:Wouldn't it be nicer if, instead, it simply returned typeof(aa[key]).init if the key was not present in the array?But then you can't tell wheter the key was present and the value was init, or it was not present at all.
Jan 25 2008
On 1/25/08, Ary Borenszweig <ary esperanto.org.ar> wrote:Janice Caron wrote:If knowing that is important, you must use "in", as you always have done. I wasn't for one moment suggesting deprecating "in". However, there are plenty of circumstances where the distinction is unimportant. Another approach would be to specify the default at the time you make the call (instead of relying on init). Of course, for that you'd need a new syntax - e.g. aa[key; defaultValue] or aa[key ? defaultValue] or aa[key else defaultValue] etc. But yeah - under the first idea, if you really need to tell whether the key was present and the value was init, you'd just do key in init i.e. no change. Existing code still does the job.Wouldn't it be nicer if, instead, it simply returned typeof(aa[key]).init if the key was not present in the array?But then you can't tell wheter the key was present and the value was init, or it was not present at all.
Jan 25 2008
Janice Caron, el 25 de enero a las 14:58 me escribiste:On 1/25/08, Ary Borenszweig <ary esperanto.org.ar> wrote:aa.get(key, defaultvalue) (a la python)? I think your proposed syntax, well, besides being a new syntax =P, it's not clear because is not the key which will be replaced for a default value, the default value "else" clause should be outside the [] (if a new syntax is wanted), which I think is hard to do. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- HOMBRE DESNUDO AMENAZA A LOS VECINOS CON UNA "KATANA" DESDE SU BALCON -- Crónica TVJanice Caron wrote:If knowing that is important, you must use "in", as you always have done. I wasn't for one moment suggesting deprecating "in". However, there are plenty of circumstances where the distinction is unimportant. Another approach would be to specify the default at the time you make the call (instead of relying on init). Of course, for that you'd need a new syntax - e.g. aa[key; defaultValue] or aa[key ? defaultValue] or aa[key else defaultValue] etc.Wouldn't it be nicer if, instead, it simply returned typeof(aa[key]).init if the key was not present in the array?But then you can't tell wheter the key was present and the value was init, or it was not present at all.
Jan 25 2008
On 1/25/08, Leandro Lucarella <llucax gmail.com> wrote:I think your proposed syntax ... it's not clearI'm not proposing a syntax, I'm proposing an idea. I don't care about the syntax. At least, so long as it's not ((p = (key in aa)) is null) ? *p : defaultValue) :-)
Jan 25 2008
On 1/25/08, Janice Caron <caron800 googlemail.com> wrote:((p = (key in aa)) is null) ? *p : defaultValue)Spot the deliberate (ahem) mistake! Hint - there's a missing exclamation mark somewhere. :-) Seriously, really I just want aa[key] to return some default value. Whether that's value.init, or some settable property within AAs, or if it could somehow be expressed at the call site - any or all of those options would be fine.
Jan 25 2008
Janice Caron wrote:On 1/25/08, Janice Caron <caron800 googlemail.com> wrote:Oskar gave you a solution. T get(T,U)(T[U] aa, U key) { T* ptr = key in aa; if (ptr) return *ptr; return T.init; } T get(T,U,int dummy=1)(T[U] aa, U key, lazy T defaultValue) { T* ptr = key in aa; if (ptr) return *ptr; return defaultValue; } Which looks exactly like a D translation of Python's get method for dicts. Python also has setdefault, which does the same as get() but also sets the value to the specified default if it didn't exist before. I'm not wild about that name "setdefault" but anyway having the method in the std lib is good. T setdefault(T,U)(T[U] aa, U key) { T* ptr = key in aa; if (ptr) return *ptr; aa[key] = T.init; return T.init; } T setdefault(T,U,int dummy=1)(T[U] aa, U key, lazy T defaultValue) { T* ptr = key in aa; if (ptr) return *ptr; aa[key] = defaultValue return aa[key]; } --bb((p = (key in aa)) is null) ? *p : defaultValue)Spot the deliberate (ahem) mistake! Hint - there's a missing exclamation mark somewhere. :-) Seriously, really I just want aa[key] to return some default value. Whether that's value.init, or some settable property within AAs, or if it could somehow be expressed at the call site - any or all of those options would be fine.
Jan 25 2008
On 1/25/08, Janice Caron <caron800 googlemail.com> wrote:But yeah - under the first idea, if you really need to tell whether the key was present and the value was init, you'd just do key in init i.e. no change. Existing code still does the job.Typo. I meant key in aa
Jan 25 2008
Janice Caron Wrote:The big problem for me with associative arrays is that I often have to write ugly code like: [snip] if the key was not present in the array? Or perhaps an even more exotic syntax like auto val = aa[key; defaultValue]; might work.If the behavior is defined at the location of the index call, I'd be very happy with adding exotic syntax similar to what you propose. Another candidate would be to make behavior with invalid indexing a policy that's included in the AA definition.
Jan 25 2008