Re: Associative arrays with keys containing mutable indirections
On 10/30/17 6:49 AM, Tony wrote: I prefer the built-in associative array over using some template library. It has the clean look and ease-of-use that you get with a similar data structure in dynamic languages like Python. I consider it a top feature of D. There is a misunderstanding here. The goal is to replace the implementation of the builtin AA with a template implementation. Right now there are some "magic" pieces of the AA that are helped by the compiler. If we can do this all in a template library, then the syntax doesn't change at all, but now you have better abilities to customize the builtin AAs, or use more specialized templates in some cases. -Steve
Re: Associative arrays with keys containing mutable indirections
I prefer the built-in associative array over using some template library. It has the clean look and ease-of-use that you get with a similar data structure in dynamic languages like Python. I consider it a top feature of D.
Re: Associative arrays with keys containing mutable indirections
On Sunday, October 29, 2017 22:24:57 Nordlöw via Digitalmars-d-learn wrote: > Shouldn't associative arrays with key types (K) having mutable > indirections (std.traits.hasAliasing!K) such as > > string[ubyte[]] > > be disallowed? > > If not, in what cases do we want this? Well, the built-in associative arrays _are_ kind of a mess (though the situation has improved somewhat over time), but the way that this was handled does make _some_ sense, even if it's still not correct. If you had something like string[ubyte[]] aa; pragma(msg, (typeof).string); This will print string[const(ubyte)[]] So, similar to C++'s std::map, const gets added for you underneath the hood for the keys, which does prevent _some_ bad assignments. Unfortunately, that's still not enough - it really should be immutable. For instance, void main() { string[ubyte[]] aa; ubyte[] a = [1, 2, 3]; aa[a] = "hello"; } fails to compile and gives the error q.d(5): Error: associative arrays can only be assigned values with immutable keys, not int[] but this code void main() { string[ubyte[]] aa; ubyte[] a = [1, 2, 3]; const b = a; aa[b] = "hello"; } does compile. So, the way it handles this avoids forcing you to explicitly put the const or immutable on the key type, which makes for less typing, but the fact that it's using const and not immutable is definitely a bug. Based on the error message, clearly it was acknowledged that the keys need to be immutable, but clearly that hasn't quite made it how the rest of it was implemented. IIRC, the implementation using void* and casts everywhere, so it's pretty trivial for it to break the type system if anything gets screwed up. But as I said, the built-in AAs are a mess. They work reasonably well for basic cases but start falling apart when you do stuff like use classes for keys. While the situation is better than it used to be, historically, we've had tons of bugs in the implementation, and overall, I'd argue that having AAs in the language was a mistake. It probably made more sense in the D1 days, but at this point, the only real advantage over a library type is that the built-in AAs work with AA literals, and a library type wouldn't (though with a solid DIP, I'm sure that that could be fixed). Work has been done on templatizing the AA implementation, which should help, but we'd be much better off sorting out a proper library type and encouraging its use. One of the suggestions of how to improve things has been to restrict keys for the built-in AAs to simpler types (e.g. no classes), but there hasn't been agreement on that, and we'd actually need a proper library type in Phobos before doing something like that (and the situation with Phobos and containers is its own mess). The whole AA mess comes up probably just about every dconf, and I expect that it will be sorted out eventually, but when that will be, I don't know. A big part of the question is what's going to happen with Martin's work on templatizing the implementation. It may be that that can salvage things, but in the interim, bugs in in the built-in AAs are no surprise. If anything, it's probably a miracle that they work as well as they do. - Jonathan M Davis
Re: Associative arrays
On Monday, 9 November 2015 at 04:52:37 UTC, rsw0x wrote: On Monday, 9 November 2015 at 04:29:30 UTC, Rikki Cattermole wrote: Fwiw, EMSI provides high quality containers backed by std.experimental.allocator. https://github.com/economicmodeling/containers I have a question regarding the implementation of the economicmodeling hashmap. Why must buckets be a power of two? Is it to be able to use the: hash & (buckets.length - 1) for index calculations or is there some other reason?
Re: Associative arrays
On Tuesday, 10 November 2015 at 01:29:11 UTC, Brian Schott wrote: Yes. It's a hack that gives you a modulus without having to do a modulus. It only works on powers of two. http://graphics.stanford.edu/~seander/bithacks.html#ModulusDivisionEasy
Re: Associative arrays
On Monday, 9 November 2015 at 04:52:37 UTC, rsw0x wrote: On Monday, 9 November 2015 at 04:29:30 UTC, Rikki Cattermole wrote: On 09/11/15 4:57 PM, TheFlyingFiddle wrote: [...] Nope. [...] As far as I'm aware, you are stuck using e.g. structs to emulate AA behavior. I have a VERY basic implementation here: https://github.com/rikkimax/alphaPhobos/blob/master/source/std/experimental/internal/containers/map.d Feel free to steal. Fwiw, EMSI provides high quality containers backed by std.experimental.allocator. https://github.com/economicmodeling/containers Thanks for the suggestions. I also made a hashmap using allocators some time ago that I use in-place of the built in hashmap for most of my purposes. The syntax of a custom hash map is somewhat lacking in comparison to the built in one however and I was hoping that I could either make the built in work with allocators or replace it with my own implementation. In addition to this I am building a pointer patching binary serializer and I hoped that I could make it work with the built in aa without requiring to many gc allocations. The economicmodeling one seems interesting ill try it out and see if it's better then the one I am currently using.
Re: Associative arrays
On Monday, 9 November 2015 at 21:33:09 UTC, TheFlyingFiddle wrote: On Monday, 9 November 2015 at 04:52:37 UTC, rsw0x wrote: On Monday, 9 November 2015 at 04:29:30 UTC, Rikki Cattermole wrote: Fwiw, EMSI provides high quality containers backed by std.experimental.allocator. https://github.com/economicmodeling/containers I have a question regarding the implementation of the economicmodeling hashmap. Why must buckets be a power of two? Is it to be able to use the: hash & (buckets.length - 1) for index calculations or is there some other reason? I have no idea, sorry. Schott wrote them AFAIK, he might be able to respond if he sees this.
Re: Associative arrays
On Monday, 9 November 2015 at 21:33:09 UTC, TheFlyingFiddle wrote: On Monday, 9 November 2015 at 04:52:37 UTC, rsw0x wrote: On Monday, 9 November 2015 at 04:29:30 UTC, Rikki Cattermole wrote: Fwiw, EMSI provides high quality containers backed by std.experimental.allocator. https://github.com/economicmodeling/containers I have a question regarding the implementation of the economicmodeling hashmap. Why must buckets be a power of two? Is it to be able to use the: hash & (buckets.length - 1) for index calculations or is there some other reason? Yes. It's a hack that gives you a modulus without having to do a modulus. It only works on powers of two.
Re: Associative arrays
On 09/11/15 4:57 PM, TheFlyingFiddle wrote: I have a few questions about the pseudo built in associative arrays. 1. Is it possible to have the built in associative array use a custom allocator from std.experimental.allocator to service it's allocation needs? Nope. 2. A while ago I read on the newsgroup a while back that there was a plan to make it possible for a user to swap out the standard associative array implementation by modifying druntime and or implementing some linker functions. Have this been done yet? And if so what must I do to swap the implementation? As far as I'm aware, you are stuck using e.g. structs to emulate AA behavior. I have a VERY basic implementation here: https://github.com/rikkimax/alphaPhobos/blob/master/source/std/experimental/internal/containers/map.d Feel free to steal.
Re: Associative arrays
On Monday, 9 November 2015 at 04:29:30 UTC, Rikki Cattermole wrote: On 09/11/15 4:57 PM, TheFlyingFiddle wrote: [...] Nope. [...] As far as I'm aware, you are stuck using e.g. structs to emulate AA behavior. I have a VERY basic implementation here: https://github.com/rikkimax/alphaPhobos/blob/master/source/std/experimental/internal/containers/map.d Feel free to steal. Fwiw, EMSI provides high quality containers backed by std.experimental.allocator. https://github.com/economicmodeling/containers
Re: Associative arrays, multithreading, Rebindable
Jack Applegame: Should Rebindable to support associative arrays? I guess so. But how to implement it? Bye, bearophile
Re: Associative arrays, multithreading, Rebindable
On Saturday, 12 April 2014 at 09:18:12 UTC, bearophile wrote: Jack Applegame: Should Rebindable to support associative arrays? I guess so. But how to implement it? Bye, bearophile May be just like Rebindable for classes?
Re: Associative arrays, multithreading, Rebindable
On Saturday, 12 April 2014 at 09:18:12 UTC, bearophile wrote: Jack Applegame: Should Rebindable to support associative arrays? I guess so. But how to implement it? Bye, bearophile Related: Rebindable supports arrays (Which makes no sense) https://issues.dlang.org/show_bug.cgi?id=12046 Quote: It *might* make sense with associative arrays though... Not sure
Re: associative arrays
dennis luehring wrote: so your FileDelete would not return an FileDoesNotExists-Error? Correct. would it not help to better understand big code if the remove would be renamed to remove_existing or to add something like this? Maybe. You possibly know about the `rm'-command of *nix-like systems and the by typo inserted space, which makes `rm -r *.obj' to `rm -r * .obj' This will certainly result in the nice error-message: cannot remove `.obj': No such file or directory Therefore: trying to help a minority possibly routes the majority. -manfred
Re: associative arrays
Looks like this is fixed for 2.058. https://github.com/D-Programming-Language/dmd/commit/3e23b0f5834acb32eaee20d88c30ead7e03bb2f4 On 08/01/2012 3:43 AM, Jonathan M Davis wrote: On Sunday, January 08, 2012 03:24:22 Kapps wrote: Ah, found the bug / pull request. https://github.com/D-Programming-Language/dmd/pull/597 http://d.puremagic.com/issues/show_bug.cgi?id=4523 Ah, TDPL says that it returns bool. Well, then it definitely needs to be changed, and it's good to see that that there's a pull request for it. So, it should be fixed in the next release. In fact, the number of TDPL-related bugs fixed for the next release should be quite high, which is great. - Jonathan M Davis
Re: associative arrays
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. but then it should be called optional_remove - because it mabye removes its like file_delete, DeleteFile (and all the others) on non existing files - why is there an exception/error neeeded if missing? the maybe-situation is not that often used in good code - because you can't find your errors if many routines would work like remove
Re: associative arrays
On Sun, 08 Jan 2012 08:40:27 -0500, Jonathan M Davis jmdavisp...@gmx.com wrote: On Sunday, January 08, 2012 14:24:32 simendsjo wrote: Thanks for your clarifications. Does this mean even this is undefined? aa[a] = new C(); auto c = a in aa; aa[b] = new C(); // Using c here is undefined as an element was added to aa Yes. Depending on the current implementation of AAs and the state of aa when b is added to it, c could still point to exactly what it did before, or aa could have been rehashed, which could move any or all of its elements around, in which case who knows what c points to. Actually, not invalid for the current implementation. I don't know if it's stated whether an AA specifically requires that elements do not re-associate on a rehash. There are certain hash implementations (such as ones that involve a single array), which would invalidate pointers on a rehash. So there is the potential (if it's not a stated requirement to the contrary in the spec) that some future AA implementation would invalidated references. However, I'd say it's unlikely this would happen. BTW, dcollections' HashMap, HashSet, and HashMultiset do guarantee that adding elements does not invalidated cursors (dcollections' safe version of pointers) as long as you use the default Hash implementation. However, I just noticed this is not stated anywhere in the docs (will fix). -Steve
Re: associative arrays
On Monday, January 09, 2012 09:25:14 Steven Schveighoffer wrote: Actually, not invalid for the current implementation. I don't know if it's stated whether an AA specifically requires that elements do not re-associate on a rehash. Well, like I said, it depends on the current implementation. There are hash table implementations where rehashing would invalidate the pointer returned by in, and I don't believe that the spec specificies that D's AA guarantees that rehashing doesn't do that. So in the future, it _could_ be changed to an implementation which invalidates the pointers on rehash. As such, it doesn't really matter what the current implementation does. Relying on the current behavior is unsafe if it's not guaranteed by the spec. Now, if we want to change the spec to make such guarantees, that's fine, but I don't believe it makes them right now. Good to know what the current implementation is doing though. - Jonathan m Davis
Re: associative arrays
On 1/9/12, Steven Schveighoffer schvei...@yahoo.com wrote: BTW, dcollections' HashMap, HashSet, and HashMultiset do guarantee that adding elements does not invalidated cursors (dcollections' safe version of pointers) as long as you use the default Hash implementation. However, I just noticed this is not stated anywhere in the docs (will fix). Funny, I was looking at the docs a few days ago and it said Adding an element can invalidate cursors depending on the implementation., so I just assumed it did invalidate the cursors. I do think those are dcollections v1 docs though. Anyway glad to hear from you about this.
Re: associative arrays
On Mon, 09 Jan 2012 13:35:26 -0500, Andrej Mitrovic andrej.mitrov...@gmail.com wrote: On 1/9/12, Steven Schveighoffer schvei...@yahoo.com wrote: BTW, dcollections' HashMap, HashSet, and HashMultiset do guarantee that adding elements does not invalidated cursors (dcollections' safe version of pointers) as long as you use the default Hash implementation. However, I just noticed this is not stated anywhere in the docs (will fix). Funny, I was looking at the docs a few days ago and it said Adding an element can invalidate cursors depending on the implementation., so I just assumed it did invalidate the cursors. Yeah, I could have sworn I stated somewhere that the current implementation doesn't invalidate cursors, but apparently it's not stated. I think the docs need a lot of TLC before the first release. Some day when I have time... To clarify what I plan to do, the add doc will say something like adding an element can invalidate cursors depending on the implementation, however the default implementation guarantees not to invalidate them. I don't want to specifically disallow implementations which do invalidate (dcollections' implementations are pluggable so anyone can replace the internals). I do think those are dcollections v1 docs though. Anyway glad to hear from you about this. The D2 docs are somewhat leftover from D1 version. However, I do remember when implementing the hash code that it purposely does not invalidate cursors on a rehash. Ranges can be invalidated, however. Given the implementation, it's actually faster *not* to invalidate them when rehashing because I just relink all the link-list nodes instead of reallocating them. -Steve
Re: associative arrays
Ok, allow me to temporarily hijack again and ask: Would you mind adding opIn_r (or rather the newer opBinaryRight with in) that forwards to contains() for the HashSet and similar hash-based classes that define contains()? It would make porting code that uses builtin hashes to your own implementation easier.
Re: associative arrays
On Mon, 09 Jan 2012 14:57:36 -0500, Andrej Mitrovic andrej.mitrov...@gmail.com wrote: Ok, allow me to temporarily hijack again and ask: Would you mind adding opIn_r (or rather the newer opBinaryRight with in) that forwards to contains() for the HashSet and similar hash-based classes that define contains()? It would make porting code that uses builtin hashes to your own implementation easier. Could this be you? http://www.dsource.org/projects/dcollections/ticket/18 If so, this means you are OK with the last suggestion I made? -Steve
Re: associative arrays
On 1/9/12, Steven Schveighoffer schvei...@yahoo.com wrote: Could this be you? Ah, yes. I didn't even notice you've replied to that, sorry. Yes, I'm ok with it.
Re: associative arrays
dennis luehring wrote: why is there an exception/error neeeded if missing? Exceptions or errors are not _needed_. Their existence stems from the modell under which the user of the operation _has_ to think about the operation, especially whether it is a:only the outcome of the operation or b:the amount of work to get to this outcome and maybe c:at runtime has to be known, whether the object exists. Jesse Phillips wrote: I have a lot of if(exists) remove() in my code As one can see, Jesse does not know, whether the object exists and has to ask, before he in fact removes the object, i.e. doubled access to the file, which may cause a slowdown. As Jesse states the designer of the API has made up false assumptions about his knowledge, described in c:, _and_ his interests, described in b:. Jesse is interested only in the outcome of the operation, as described in a:, Therefore the likely answer to your question stated at the beginning is: the designer of the API made a mistake. -manfred
Re: associative arrays
Am 09.01.2012 22:08, schrieb Manfred Nowak: dennis luehring wrote: why is there an exception/error neeeded if missing? Exceptions or errors are not _needed_. Their existence stems from the modell under which the user of the operation _has_ to think about the operation, especially whether it is a:only the outcome of the operation or b:the amount of work to get to this outcome and maybe c:at runtime has to be known, whether the object exists. Jesse Phillips wrote: I have a lot of if(exists) remove() in my code As one can see, Jesse does not know, whether the object exists and has to ask, before he in fact removes the object, i.e. doubled access to the file, which may cause a slowdown. so your FileDelete would not return an FileDoesNotExists-Error? it isn't always clear what is ok to happen - there are million types of remove-like-semantic, an Jesse's scenario is one type of usage, which other type of remove allows silently non-remove-removes? STL? Python, etc. (how do others handle such cases) would it not help to better understand big code if the remove would be renamed to remove_existing or to add something like this?
Re: associative arrays
On 1/7/2012 8:54 PM, bearophile wrote: 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. a.remove(x) doesn't fail though. It successfully satisfies its own postconditions by placing a in a state whereby it no longer contains x. The real source of bugs in this example is using hardcoded strings instead of named constants. :) Besides, one frequently doesn't know if (x in a) or not ahead of time. Think of evicting some computed intermediate results from a cache when you detect that the underlying resource has changed, for instance. In fact, it's really rare for an item to be removed from a long-lived collection anywhere near the point that it was added. Insisting on existence before removal clutters up the code for an extremely common use case. FWIW, Java's Map and .NET's IDictionary also handle this situation silently. Regards, ~Stephen
Re: associative arrays
On Sunday, January 08, 2012 01:39:24 Kapps wrote: For most languages (such as C# and maybe Java), the Remove method on collections returns a boolean indicating whether it was removed. So you could write: enforce(MyAA.remove(lenght)) or bool Result = MyAA.remove(lenght); assert(Result); I'm not sure why it doesn't in D, but I thought I remembered seeing a pull request or change that added it. Maybe I'm imagining things since I can't find it now. There _is_ extra cost in returning bool rather than void, but I'm not at all sure that it's unreasonable to incur that cost. std.container.RedBlackTree's remove function returns how many elements were removed. Other functions in Phobos do similar in similar situations. It probably merits an enhancement request. - Jonathan M Davis
Re: associative arrays
Ah, found the bug / pull request. https://github.com/D-Programming-Language/dmd/pull/597 http://d.puremagic.com/issues/show_bug.cgi?id=4523 On 08/01/2012 1:39 AM, Kapps wrote: For most languages (such as C# and maybe Java), the Remove method on collections returns a boolean indicating whether it was removed. So you could write: enforce(MyAA.remove(lenght)) or bool Result = MyAA.remove(lenght); assert(Result); I'm not sure why it doesn't in D, but I thought I remembered seeing a pull request or change that added it. Maybe I'm imagining things since I can't find it now. On 07/01/2012 4: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? After all if i write: writeln(arr1[xxx]); runtime expresses its disappointment...
Re: associative arrays
On Sunday, January 08, 2012 03:24:22 Kapps wrote: Ah, found the bug / pull request. https://github.com/D-Programming-Language/dmd/pull/597 http://d.puremagic.com/issues/show_bug.cgi?id=4523 Ah, TDPL says that it returns bool. Well, then it definitely needs to be changed, and it's good to see that that there's a pull request for it. So, it should be fixed in the next release. In fact, the number of TDPL-related bugs fixed for the next release should be quite high, which is great. - Jonathan M Davis
Re: associative arrays
On 08.01.2012 10:43, Jonathan M Davis wrote: On Sunday, January 08, 2012 03:24:22 Kapps wrote: Ah, found the bug / pull request. https://github.com/D-Programming-Language/dmd/pull/597 http://d.puremagic.com/issues/show_bug.cgi?id=4523 Ah, TDPL says that it returns bool. Well, then it definitely needs to be changed, and it's good to see that that there's a pull request for it. So, it should be fixed in the next release. In fact, the number of TDPL-related bugs fixed for the next release should be quite high, which is great. - Jonathan M Davis Wouldn't it make sense to return a pointer to the item being removed/null? This way you can continue to work with the item, and it would be consistent with `in`. if (auto item = aa.remove(key)) { // some additional work on item } else { // not found // throw or something }
Re: associative arrays
simendsjo wrote: Wouldn't it make sense to return a pointer to the item being removed/null? According to the docs this is the intended behavior. -manfred
Re: associative arrays
On 08.01.2012 11:09, Manfred Nowak wrote: simendsjo wrote: Wouldn't it make sense to return a pointer to the item being removed/null? According to the docs this is the intended behavior. -manfred The only mention I can see of remove is at the top, and it doesn't state return value: http://dlang.org/hash-map.html The pull changes the return value to bool: https://github.com/9rnsr/dmd/commit/f3cc75445775927e2036054811afb686cf4f1624
Re: associative arrays
On Sunday, January 08, 2012 11:02:41 simendsjo wrote: On 08.01.2012 10:43, Jonathan M Davis wrote: On Sunday, January 08, 2012 03:24:22 Kapps wrote: Ah, found the bug / pull request. https://github.com/D-Programming-Language/dmd/pull/597 http://d.puremagic.com/issues/show_bug.cgi?id=4523 Ah, TDPL says that it returns bool. Well, then it definitely needs to be changed, and it's good to see that that there's a pull request for it. So, it should be fixed in the next release. In fact, the number of TDPL-related bugs fixed for the next release should be quite high, which is great. - Jonathan M Davis Wouldn't it make sense to return a pointer to the item being removed/null? This way you can continue to work with the item, and it would be consistent with `in`. if (auto item = aa.remove(key)) { // some additional work on item } else { // not found // throw or something } Since the element has been removed from the container, what would the pointer point to? The element doesn't exist anymore. - Jonathan m Davis
Re: associative arrays
On 08.01.2012 11:27, Jonathan M Davis wrote: On Sunday, January 08, 2012 11:02:41 simendsjo wrote: On 08.01.2012 10:43, Jonathan M Davis wrote: On Sunday, January 08, 2012 03:24:22 Kapps wrote: Ah, found the bug / pull request. https://github.com/D-Programming-Language/dmd/pull/597 http://d.puremagic.com/issues/show_bug.cgi?id=4523 Ah, TDPL says that it returns bool. Well, then it definitely needs to be changed, and it's good to see that that there's a pull request for it. So, it should be fixed in the next release. In fact, the number of TDPL-related bugs fixed for the next release should be quite high, which is great. - Jonathan M Davis Wouldn't it make sense to return a pointer to the item being removed/null? This way you can continue to work with the item, and it would be consistent with `in`. if (auto item = aa.remove(key)) { // some additional work on item } else { // not found // throw or something } Since the element has been removed from the container, what would the pointer point to? The element doesn't exist anymore. - Jonathan m Davis I was thinking it could be a shorthand for the following: auto item = key in aa; if (item) key.remove(key);
Re: associative arrays
On 1/8/12, simendsjo simend...@gmail.com wrote: Wouldn't it make sense to return a pointer to the item being removed/null? Seems like that would be even more costly. Personally I think returning bool is unnecessary, if we really want to know if something is in the hash we can check with the `in` operator. I filed that bug ages ago simply because it was in TDPL, but I didn't really give it much thought.
Re: associative arrays
simendsjo wrote: it doesn't state return value Yes, I haven't read carefully enough. -manfred
Re: associative arrays
On 08.01.2012 12:18, Jonathan M Davis wrote: On Sunday, January 08, 2012 11:33:51 simendsjo wrote: I was thinking it could be a shorthand for the following: auto item = key in aa; if (item) key.remove(key); I take it that you then intend to use item after that? I'm not sure that item is actually valid at that point. It points to memory which _was_ inside of aa but may or may not be now, depending on the AA implementation, and it may or may not be reused by aa. Because it's on the GC heap, the memory itself won't be invalid, but the memory could be reused by the AA for another element, depending on its implementation. If you're lucky, it's memory that's just sitting on the GC heap and now unrelated to the AA, but I wouldn't bet on it. I would _not_ consider that to be good code. It's just asking for trouble. - Jonathan M Davis Ah.. This should be documented in http://dlang.org/hash-map.html The only documentation for remove is: Particular keys in an associative array can be removed with the remove function: b.remove(hello);
Re: associative arrays
On Sunday, January 08, 2012 12:35:27 simendsjo wrote: On 08.01.2012 12:18, Jonathan M Davis wrote: On Sunday, January 08, 2012 11:33:51 simendsjo wrote: I was thinking it could be a shorthand for the following: auto item = key in aa; if (item) key.remove(key); I take it that you then intend to use item after that? I'm not sure that item is actually valid at that point. It points to memory which _was_ inside of aa but may or may not be now, depending on the AA implementation, and it may or may not be reused by aa. Because it's on the GC heap, the memory itself won't be invalid, but the memory could be reused by the AA for another element, depending on its implementation. If you're lucky, it's memory that's just sitting on the GC heap and now unrelated to the AA, but I wouldn't bet on it. I would _not_ consider that to be good code. It's just asking for trouble. - Jonathan M Davis Ah.. This should be documented in http://dlang.org/hash-map.html The only documentation for remove is: Particular keys in an associative array can be removed with the remove function: b.remove(hello); I confess that it's one of those things that I would have thought would have been fairly obvious, but it certainly wouldn't hurt to add it. The documentation does tend to be sparse of details in any case. - Jonathan M Davis
Re: associative arrays
On 08.01.2012 12:57, Jonathan M Davis wrote: On Sunday, January 08, 2012 12:35:27 simendsjo wrote: On 08.01.2012 12:18, Jonathan M Davis wrote: On Sunday, January 08, 2012 11:33:51 simendsjo wrote: I was thinking it could be a shorthand for the following: auto item = key in aa; if (item) key.remove(key); I take it that you then intend to use item after that? I'm not sure that item is actually valid at that point. It points to memory which _was_ inside of aa but may or may not be now, depending on the AA implementation, and it may or may not be reused by aa. Because it's on the GC heap, the memory itself won't be invalid, but the memory could be reused by the AA for another element, depending on its implementation. If you're lucky, it's memory that's just sitting on the GC heap and now unrelated to the AA, but I wouldn't bet on it. I would _not_ consider that to be good code. It's just asking for trouble. - Jonathan M Davis Ah.. This should be documented in http://dlang.org/hash-map.html The only documentation for remove is: Particular keys in an associative array can be removed with the remove function: b.remove(hello); I confess that it's one of those things that I would have thought would have been fairly obvious, but it certainly wouldn't hurt to add it. The documentation does tend to be sparse of details in any case. - Jonathan M Davis Certainly not obvious to me :) auto c = new C(); C[string] aa; aa[c] = c; aa.remove(c); I guess using c from this point is valid, but if the only reference to c was inside the aa (and we got c using `in`), using c would have been undefined..?
Re: associative arrays
On Sunday, January 08, 2012 13:06:06 simendsjo wrote: Certainly not obvious to me :) Well, what's obvious to one person is not always obvious to another. I'm sure that there are plenty of things that Walter thinks should be perfectly obvious which 90% of programmers would never think of. A lot of it depends on what you're experience level is and what you have experience in. In this case, it's very much like dealing with C++ iterators, so if you're used to dealing with them and when they do or don't get invalidate, then the situation with in and remove is probably quite straightforward and intuitive. auto c = new C(); C[string] aa; aa[c] = c; aa.remove(c); I guess using c from this point is valid, but if the only reference to c was inside the aa (and we got c using `in`), using c would have been undefined..? Using c is valid regardless. The problem is the in operator. It returns a pointer to the element inside of the AA. So, if you did C* d = aa[c]; then d would be a pointer to a reference to a C, and after the call to remove, the pointer is pointing to memory which may or may not be part of the AA anymore and which may or may not hold a reference to what c refers to. It's bit like doing this int* a() { int b; return b; } though the compiler should catch this, since it's obviously wrong. In both cases, you're referring to memory which your really not supposed to be accessing anymore and may point to invalid memory. The case of the AA probably isn't as bad, since either you're pointing to memory on the GC which isn't part of the AA (but hasn't been collected, since you have a pointer to it), or you're pointing to an element in the AA which may still be the same as it was before it was removed, or it may be another element, or it may be garbage memory. You really don't know. It's undefined and therefore shouldn't be used. I don't believe that it's ever safe to assume that the pointer returned by the in operator is still valid after the AA that it comes from has had an element added or removed. It's the same with iterators or ranges with many iterators and ranges. If they point to elements within a container, and that container is altered, they're invalidated and aren't safe to use. So, your example is fine, because it doesn't involve the in operator, and therefore doesn't involve any pointers into the AA. It's only once you have pointers into the AA that you get into trouble. - Jonathan M Davis
Re: associative arrays
On 08.01.2012 13:49, Jonathan M Davis wrote: On Sunday, January 08, 2012 13:06:06 simendsjo wrote: Certainly not obvious to me :) Well, what's obvious to one person is not always obvious to another. I'm sure that there are plenty of things that Walter thinks should be perfectly obvious which 90% of programmers would never think of. A lot of it depends on what you're experience level is and what you have experience in. In this case, it's very much like dealing with C++ iterators, so if you're used to dealing with them and when they do or don't get invalidate, then the situation with in and remove is probably quite straightforward and intuitive. auto c = new C(); C[string] aa; aa[c] = c; aa.remove(c); I guess using c from this point is valid, but if the only reference to c was inside the aa (and we got c using `in`), using c would have been undefined..? Using c is valid regardless. The problem is the in operator. It returns a pointer to the element inside of the AA. So, if you did C* d = aa[c]; then d would be a pointer to a reference to a C, and after the call to remove, the pointer is pointing to memory which may or may not be part of the AA anymore and which may or may not hold a reference to what c refers to. It's bit like doing this int* a() { int b; returnb; } though the compiler should catch this, since it's obviously wrong. In both cases, you're referring to memory which your really not supposed to be accessing anymore and may point to invalid memory. The case of the AA probably isn't as bad, since either you're pointing to memory on the GC which isn't part of the AA (but hasn't been collected, since you have a pointer to it), or you're pointing to an element in the AA which may still be the same as it was before it was removed, or it may be another element, or it may be garbage memory. You really don't know. It's undefined and therefore shouldn't be used. I don't believe that it's ever safe to assume that the pointer returned by the in operator is still valid after the AA that it comes from has had an element added or removed. It's the same with iterators or ranges with many iterators and ranges. If they point to elements within a container, and that container is altered, they're invalidated and aren't safe to use. So, your example is fine, because it doesn't involve the in operator, and therefore doesn't involve any pointers into the AA. It's only once you have pointers into the AA that you get into trouble. - Jonathan M Davis Thanks for your clarifications. Does this mean even this is undefined? aa[a] = new C(); auto c = a in aa; aa[b] = new C(); // Using c here is undefined as an element was added to aa
Re: associative arrays
On Sunday, January 08, 2012 14:24:32 simendsjo wrote: Thanks for your clarifications. Does this mean even this is undefined? aa[a] = new C(); auto c = a in aa; aa[b] = new C(); // Using c here is undefined as an element was added to aa Yes. Depending on the current implementation of AAs and the state of aa when b is added to it, c could still point to exactly what it did before, or aa could have been rehashed, which could move any or all of its elements around, in which case who knows what c points to. - Jonathan M Davis
Re: associative arrays
Jonathan M Davis wrote: In this case, it's very much like dealing with C++ iterators A relevant part of Andrei's thread on associative arrays iteration: http://www.digitalmars.com/d/archives/digitalmars/D/associative_arrays_ iteration_is_finally_here_99576.html#N99614 -manfred
Re: associative arrays
Based on these arguments does that mean std.file.remove should not be throwing when a file doesn't exist? Or more precisely should I add a bugzilla entry to change this. I certainly have a lot of if(exists) remove() in my code and end up having to change where I just use remove(). On Sunday, 8 January 2012 at 05:03:45 UTC, Manfred Nowak wrote: Jonathan M Davis wrote: So, as far as I can tell, the current situation is more efficient There are some more arguments: 1) Different threads might want to `remove' the same key from the AA. I don't see a reason why only the first served thread should complete the operation without an error. 2) Because there is only one operation for insertion of a key into an AA, only one operation should be used for removing that key. Note: This argument vanishes if insertions are divided in a:declaration of a key as valid in that AA, b:first assignment to the value of a key, c:reassignment to the value of a key 3) Reverse operations should not implement more functionality than the reversed operation. Because `remove' is the reverse operation for inserting a key and that operation does not cause any error, neither should errors be given from `remove'. Note: Reassigning to the value of a key might very well treated as an error. -manfred
Re: associative arrays
Very interesting discussion. Tk u all.
Re: associative arrays
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
Re: associative arrays
RenatoL wrote: Would not it be better if an exception was raised? No, because exceptions are guarenteed to be slow. if i write: writeln(arr1[xxx]); runtime expresses its disappointment... I would be disappointed too, if the commands for removing and for requesting something are sequenced in that order. -manfred
Re: associative arrays
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
Re: associative arrays
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
Re: associative arrays
Jonathan M Davis wrote: [...] This sort of explanation is missing in the docs. -manfred
Re: associative arrays
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
Re: associative arrays
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.
Re: associative arrays
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
Re: associative arrays
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
Re: associative arrays
Jonathan M Davis wrote: So, as far as I can tell, the current situation is more efficient There are some more arguments: 1) Different threads might want to `remove' the same key from the AA. I don't see a reason why only the first served thread should complete the operation without an error. 2) Because there is only one operation for insertion of a key into an AA, only one operation should be used for removing that key. Note: This argument vanishes if insertions are divided in a:declaration of a key as valid in that AA, b:first assignment to the value of a key, c:reassignment to the value of a key 3) Reverse operations should not implement more functionality than the reversed operation. Because `remove' is the reverse operation for inserting a key and that operation does not cause any error, neither should errors be given from `remove'. Note: Reassigning to the value of a key might very well treated as an error. -manfred
Re: associative arrays
For most languages (such as C# and maybe Java), the Remove method on collections returns a boolean indicating whether it was removed. So you could write: enforce(MyAA.remove(lenght)) or bool Result = MyAA.remove(lenght); assert(Result); I'm not sure why it doesn't in D, but I thought I remembered seeing a pull request or change that added it. Maybe I'm imagining things since I can't find it now. On 07/01/2012 4: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? After all if i write: writeln(arr1[xxx]); runtime expresses its disappointment...
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 22:02:30 -0400, bearophile bearophileh...@lycos.com wrote: Denis Koroskin: Compute mutable copy and then cast to immutable. Am I missing something? That's possible. But it's an exceptionally dirty thing, I am not sure it works in SafeD. A well designed const system has to offer a more clean solution :-) Do you agree? Casting to immutable is the only way to create such a beast. The best way to ensure as few bugs as possible is to create the object you wish to be immutable in a function, and cast at the end before returning. This at least encapsulates the dirtiness in one function (which would probably be marked @trusted). You can also use assumeUnique (which I'm guessing is there so it can be called in safeD?). -Steve
Re: Associative arrays give compile error
Steven Schveighoffer: Casting to immutable is the only way to create such a beast. Then maybe we have to improve the language semantics to allow a better solution. See the Transients of Clojure or the larval objects of Java :-) The compiler may need to test (at compile time) that there's only one reference to the AA and its contents, and turn it into immutable. Bye, bearophile
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049).
Re: Associative arrays give compile error
On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d
Re: Associative arrays give compile error
On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way }
Re: Associative arrays give compile error
On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I get an error on every line: Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| ||=== Build finished: 14 errors, 0 warnings ===| This is a bit worrying now. I moved the array into the file that uses it but I still get the same errors. Any ideas?
Re: Associative arrays give compile error
On 05/10/2010 12:40, Bob Cowdery wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I get an error on every line: Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| ||=== Build finished: 14 errors, 0 warnings ===| This is a bit worrying now. I moved the array into the file that uses it but I still get the same errors. Any ideas? Oh dear, this is getting worse and worse. I've still got problems with a simple definition. If I take out the one with the tuple and leave in this one: enum E_MODE { LSB,// 0 USB,// 1 DSB,// 2 CWL,// 3 CWU,// 4 FMN,// 5 AM,// 6 DIGU,// 7 SPEC,// 8 DIGL,// 9 SAM,// 10 DRM// 11 } // Associative array for translation auto A_MODE = [ LSB: E_MODE.LSB, USB: E_MODE.USB, DSB: E_MODE.DSB, CWL: E_MODE.CWL, CWU: E_MODE.CWU, FMN: E_MODE.FMN, AM: E_MODE.AM, DIGU: E_MODE.DIGU, SPEC: E_MODE.SPEC, DIGL: E_MODE.DIGL, SAM: E_MODE.SAM, DRM: E_MODE.DRM ]; I get: Definitions\dspDefs.d|25|Error: non-constant expression [LSB:cast(E_MODE)0,USB:cast(E_MODE)1,DSB:cast(E_MODE)2,CWL:cast(E_MODE)3,CWU:cast(E_MODE)4,FMN:cast(E_MODE)5,AM:cast(E_MODE)6,DIGU:cast(E_MODE)7,SPEC:cast(E_MODE)8,DIGL:cast(E_MODE)9,SAM:cast(E_MODE)10,DRM:cast(E_MODE)11]| ||=== Build finished: 1 errors, 0 warnings ===| Something is seriously broken here.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 15:40:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; You are trying to declare global variable and initialize at in compile time. As far as I know, you can't initialize AA at compile time atm (this might be implemented in future though). As such, I'd recommend against using global variables (try moving it to some class or something). Anyway, you need to initialize it at some point, either manually: Tuple!(double,double)[string] A_RX_FILT; void init() { A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; } or automatically at thread startup: static this() { init(); } Hope that helps.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 15:50:44 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:40, Bob Cowdery wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I get an error on every line: Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| ||=== Build finished: 14 errors, 0 warnings ===| This is a bit worrying now. I moved the array into the file that uses it but I still get the same errors. Any ideas? Oh dear, this is getting worse and worse. I've still got problems with a simple definition. If I take out the one with the tuple and leave in this one: enum E_MODE { LSB,// 0 USB,// 1 DSB,// 2 CWL,// 3 CWU,// 4 FMN,// 5 AM,// 6 DIGU,// 7 SPEC,// 8 DIGL,// 9 SAM,// 10 DRM// 11 } // Associative array for translation auto A_MODE = [ LSB: E_MODE.LSB, USB: E_MODE.USB, DSB: E_MODE.DSB, CWL: E_MODE.CWL, CWU: E_MODE.CWU, FMN: E_MODE.FMN, AM: E_MODE.AM, DIGU: E_MODE.DIGU, SPEC: E_MODE.SPEC, DIGL: E_MODE.DIGL, SAM: E_MODE.SAM, DRM: E_MODE.DRM ]; I get: Definitions\dspDefs.d|25|Error: non-constant expression [LSB:cast(E_MODE)0,USB:cast(E_MODE)1,DSB:cast(E_MODE)2,CWL:cast(E_MODE)3,CWU:cast(E_MODE)4,FMN:cast(E_MODE)5,AM:cast(E_MODE)6,DIGU:cast(E_MODE)7,SPEC:cast(E_MODE)8,DIGL:cast(E_MODE)9,SAM:cast(E_MODE)10,DRM:cast(E_MODE)11]| ||=== Build finished: 1 errors, 0 warnings ===| Something is seriously broken here. Try using enum A_MODE instead of auto A_MODE, it should help. Sorry for confusion.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 12:50:44 +0100, Bob Cowdery wrote: On 05/10/2010 12:40, Bob Cowdery wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I get an error on every line: Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| ||=== Build finished: 14 errors, 0 warnings ===| This is a bit worrying now. I moved the array into the file that uses it but I still get the same errors. Any ideas? Oh dear, this is getting worse and worse. I've still got problems with a simple definition. If I take out the one with the tuple and leave in this one: enum E_MODE { LSB,// 0 USB,// 1 DSB,// 2 CWL,// 3 CWU,// 4 FMN,// 5 AM,// 6 DIGU,// 7 SPEC,// 8 DIGL,// 9 SAM,// 10 DRM// 11 } // Associative array for translation auto A_MODE = [ LSB: E_MODE.LSB, USB: E_MODE.USB, DSB: E_MODE.DSB, CWL: E_MODE.CWL, CWU: E_MODE.CWU, FMN: E_MODE.FMN, AM: E_MODE.AM, DIGU: E_MODE.DIGU, SPEC: E_MODE.SPEC, DIGL: E_MODE.DIGL, SAM: E_MODE.SAM, DRM: E_MODE.DRM ]; I get: Definitions\dspDefs.d|25|Error: non-constant expression [LSB:cast(E_MODE)0,USB:cast(E_MODE)1,DSB:cast(E_MODE)2,CWL:cast (E_MODE)3,CWU:cast(E_MODE)4,FMN:cast(E_MODE)5,AM:cast(E_MODE) 6,DIGU:cast(E_MODE)7,SPEC:cast(E_MODE)8,DIGL:cast(E_MODE) 9,SAM:cast(E_MODE)10,DRM:cast(E_MODE)11]| ||=== Build finished: 1 errors, 0 warnings ===| Something is seriously broken here. No, nothing is
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 15:53:55 +0400, Denis Koroskin 2kor...@gmail.com wrote: On Tue, 05 Oct 2010 15:40:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; You are trying to declare global variable and initialize at in compile time. As far as I know, you can't initialize AA at compile time atm (this might be implemented in future though). As such, I'd recommend against using global variables (try moving it to some class or something). Anyway, you need to initialize it at some point, either manually: Tuple!(double,double)[string] A_RX_FILT; void init() { A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; } or automatically at thread startup: static this() { init(); } Hope that helps. See my other reply for a better solution.
Re: Associative arrays give compile error
On 05/10/2010 13:05, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:53:55 +0400, Denis Koroskin 2kor...@gmail.com wrote: On Tue, 05 Oct 2010 15:40:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; You are trying to declare global variable and initialize at in compile time. As far as I know, you can't initialize AA at compile time atm (this might be implemented in future though). As such, I'd recommend against using global variables (try moving it to some class or something). Anyway, you need to initialize it at some point, either manually: Tuple!(double,double)[string] A_RX_FILT; void init() { A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; } or automatically at thread startup: static this() { init(); } Hope that helps. See my other reply for a better solution. Thanks very much. It compiles now. The reason I thought it was an issue was because sometime it did compile a global associative array. I need to do some homework on what 'this' does. It's clearly a powerful concept and has wider application than class constructors.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 16:32:14 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 13:05, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:53:55 +0400, Denis Koroskin 2kor...@gmail.com wrote: On Tue, 05 Oct 2010 15:40:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; You are trying to declare global variable and initialize at in compile time. As far as I know, you can't initialize AA at compile time atm (this might be implemented in future though). As such, I'd recommend against using global variables (try moving it to some class or something). Anyway, you need to initialize it at some point, either manually: Tuple!(double,double)[string] A_RX_FILT; void init() { A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; } or automatically at thread startup: static this() { init(); } Hope that helps. See my other reply for a better solution. Thanks very much. It compiles now. The reason I thought it was an issue was because sometime it did compile a global associative array. I need to do some homework on what 'this' does. It's clearly a powerful concept and has wider application than class constructors. static this is called a static constructor and can be used for classes and modules. The code in static constructor is guarantied to be called before you use that class/module, it usually happens upon thread initialization. The other solution is better though: enum A_RX_FILT = [ // just works 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ];
Re: Associative arrays give compile error
On 05/10/2010 13:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 16:32:14 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 13:05, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:53:55 +0400, Denis Koroskin 2kor...@gmail.com wrote: On Tue, 05 Oct 2010 15:40:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; You are trying to declare global variable and initialize at in compile time. As far as I know, you can't initialize AA at compile time atm (this might be implemented in future though). As such, I'd recommend against using global variables (try moving it to some class or something). Anyway, you need to initialize it at some point, either manually: Tuple!(double,double)[string] A_RX_FILT; void init() { A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; } or automatically at thread startup: static this() { init(); } Hope that helps. See my other reply for a better solution. Thanks very much. It compiles now. The reason I thought it was an issue was because sometime it did compile a global associative array. I need to do some homework on what 'this' does. It's clearly a powerful concept and has wider application than class constructors. static this is called a static constructor and can be used for classes and modules. The code in static constructor is guarantied to be called before you use that class/module, it usually happens upon thread initialization. The other solution is better though: enum A_RX_FILT = [// just works 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I'm not totally understanding that. Why can enum compute that at compile time and the thing which it is, an associative array cannot. Is it to do with where these things live.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 17:00:13 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 13:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 16:32:14 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 13:05, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:53:55 +0400, Denis Koroskin 2kor...@gmail.com wrote: On Tue, 05 Oct 2010 15:40:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; You are trying to declare global variable and initialize at in compile time. As far as I know, you can't initialize AA at compile time atm (this might be implemented in future though). As such, I'd recommend against using global variables (try moving it to some class or something). Anyway, you need to initialize it at some point, either manually: Tuple!(double,double)[string] A_RX_FILT; void init() { A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; } or automatically at thread startup: static this() { init(); } Hope that helps. See my other reply for a better solution. Thanks very much. It compiles now. The reason I thought it was an issue was because sometime it did compile a global associative array. I need to do some homework on what 'this' does. It's clearly a powerful concept and has wider application than class constructors. static this is called a static constructor and can be used for classes and modules. The code in static constructor is guarantied to be called before you use that class/module, it usually happens upon thread initialization. The other solution is better though: enum A_RX_FILT = [// just works 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I'm not totally understanding that. Why can enum compute that at compile time and the thing which it is, an associative array cannot. Is it to do with where these things live. Let's say it's a limitation of dmd compiler. I'll submit a bug report.
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 09:00:13 -0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 13:45, Denis Koroskin wrote: static this is called a static constructor and can be used for classes and modules. The code in static constructor is guarantied to be called before you use that class/module, it usually happens upon thread initialization. The other solution is better though: enum A_RX_FILT = [// just works 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I'm not totally understanding that. Why can enum compute that at compile time and the thing which it is, an associative array cannot. Is it to do with where these things live. I'd be very wary of this solution. Recently, enum has been shown to construct itself on every use. So what I think is happening is every time you use A_RX_FILT, it's building a brand new AA (you can verify this by looking at the disassembly). I'd recommend the static this solution in order to ensure you are not accidentally killing performance by just using that AA. A while back, Don suggested that all literals should be considered immutable. I agree with him, but Walter still doesn't. If all literals are immutable, then they could be truly constructed at compile-time. -Steve
Re: Associative arrays give compile error
On 05/10/2010 15:14, Steven Schveighoffer wrote: On Tue, 05 Oct 2010 09:00:13 -0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 13:45, Denis Koroskin wrote: static this is called a static constructor and can be used for classes and modules. The code in static constructor is guarantied to be called before you use that class/module, it usually happens upon thread initialization. The other solution is better though: enum A_RX_FILT = [// just works 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I'm not totally understanding that. Why can enum compute that at compile time and the thing which it is, an associative array cannot. Is it to do with where these things live. I'd be very wary of this solution. Recently, enum has been shown to construct itself on every use. So what I think is happening is every time you use A_RX_FILT, it's building a brand new AA (you can verify this by looking at the disassembly). I'd recommend the static this solution in order to ensure you are not accidentally killing performance by just using that AA. A while back, Don suggested that all literals should be considered immutable. I agree with him, but Walter still doesn't. If all literals are immutable, then they could be truly constructed at compile-time. -Steve I'm happy with the static this solution so will leave well alone. I generally keep mutable and immutable data structures apart so I tend to agree that literals should be immutable although of course I'm not aware of the pros and cons. bob
Re: Associative arrays give compile error
Denis Koroskin: import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Now Tuples accept the natural syntax too: writeln(result[0], , result[1]); Bob Cowdery: enum E_MODE { LSB,// 0 USB,// 1 DSB,// 2 CWL,// 3 CWU,// 4 FMN,// 5 AM,// 6 DIGU,// 7 SPEC,// 8 DIGL,// 9 SAM,// 10 DRM// 11 } // Associative array for translation auto A_MODE = [ LSB: E_MODE.LSB, USB: E_MODE.USB, DSB: E_MODE.DSB, CWL: E_MODE.CWL, CWU: E_MODE.CWU, FMN: E_MODE.FMN, AM: E_MODE.AM, DIGU: E_MODE.DIGU, SPEC: E_MODE.SPEC, DIGL: E_MODE.DIGL, SAM: E_MODE.SAM, DRM: E_MODE.DRM ]; I suggest code similar to: enum E_MODE { LSB, // 0 USB, // 1 DSB, // 2 CWL, // 3 CWU, // 4 FMN, // 5 AM, // 6 DIGU, // 7 SPEC, // 8 DIGL, // 9 SAM, // 10 DRM // 11 } void main() { // associative array for translation with (E_MODE) immutable auto a_mode = [ LSB: LSB, USB: USB, DSB: DSB, CWL: CWL, CWU: CWU, FMN: FMN, AM: AM, DIGU: DIGU, SPEC: SPEC, DIGL: DIGL, SAM: SAM, DRM: DRM ]; } Bye, bearophile
Re: Associative arrays give compile error
enum E_MODE { LSB, // 0 USB, // 1 DSB, // 2 CWL, // 3 CWU, // 4 FMN, // 5 AM, // 6 DIGU, // 7 SPEC, // 8 DIGL, // 9 SAM, // 10 DRM // 11 } void main() { // associative array for translation with (E_MODE) immutable auto a_mode = [ LSB: LSB, USB: USB, DSB: DSB, CWL: CWL, CWU: CWU, FMN: FMN, AM: AM, DIGU: DIGU, SPEC: SPEC, DIGL: DIGL, SAM: SAM, DRM: DRM ]; } That code of mine is not good. The following version is more DRY, and in theory it's a better, but in practice it doesn't work: import std.stdio: writeln; enum E_MODE { LSB, USB, DSB, CWL, CWU, FMN, AM, DIGU, SPEC, DIGL, SAM, DRM } /*immutable*/ E_MODE[string] a_mode; static this () { foreach (m; __traits(allMembers, E_MODE)) mixin(`a_mode[` ~ m ~ `] = E_MODE.` ~ m ~ `;`); } void main() { writeln(a_mode); } Bye, bearophile
Re: Associative arrays give compile error
/*immutable*/ E_MODE[string] a_mode; static this () { foreach (m; __traits(allMembers, E_MODE)) mixin(`a_mode[` ~ m ~ `] = E_MODE.` ~ m ~ `;`); } How do you build an immutable AA that is global or local to a function? Bye, bearophile
Re: Associative arrays give compile error
On Wed, 06 Oct 2010 03:45:11 +0400, bearophile bearophileh...@lycos.com wrote: /*immutable*/ E_MODE[string] a_mode; static this () { foreach (m; __traits(allMembers, E_MODE)) mixin(`a_mode[` ~ m ~ `] = E_MODE.` ~ m ~ `;`); } How do you build an immutable AA that is global or local to a function? Bye, bearophile I found the following to work fine: K[V] assocArray = createAssocArray(); K[V] createAssocArray() { K[V] assocArray = [ k1: v1, k2: v2, ... ]; return assocArray; } No idea why the following: K[V] assocArray = [ k1: v1, k2: v2, ... ]; doesn't work directly for global scope.
Re: Associative arrays give compile error
Denis Koroskin: I found the following to work fine: K[V] assocArray = createAssocArray(); K[V] createAssocArray() { K[V] assocArray = [ k1: v1, k2: v2, ... ]; return assocArray; } Thank you for your answer. But I need to compute it, so I don't have just an AA literal. And I'd like it to be immutable :-) Bye, bearophile
Re: Associative arrays give compile error
On Wed, 06 Oct 2010 04:14:37 +0400, bearophile bearophileh...@lycos.com wrote: Denis Koroskin: I found the following to work fine: K[V] assocArray = createAssocArray(); K[V] createAssocArray() { K[V] assocArray = [ k1: v1, k2: v2, ... ]; return assocArray; } Thank you for your answer. But I need to compute it, so I don't have just an AA literal. And I'd like it to be immutable :-) Bye, bearophile Compute mutable copy and then cast to immutable. Am I missing something?
Re: Associative arrays give compile error
Denis Koroskin: Compute mutable copy and then cast to immutable. Am I missing something? That's possible. But it's an exceptionally dirty thing, I am not sure it works in SafeD. A well designed const system has to offer a more clean solution :-) Do you agree? Bye, bearophile
Re: associative arrays: to sort or not to sort?
Hello Mario, Unless JSON requiers that the keys be in some order, No, JSON does not require the names of an object to be in alphabetical order. the correct solution is to make the check order independent. For example: string s = CallReturningJSON(); s = replace(s,`a:23.54`, `X`); s = replace(s,`b:0.0012`, `X`); s = replace(s,`{nested:{X,X}}`, `X`); s = replace(s,`goodbye:[true,or,false,[test,42,X]]`, `X`); s = replace(s,`array:[12,null,{}]`, `Y`); s = replace(s,is\n\ngreat, `Z`); s = replace(s,`json:Z`, `Y`); s = replace(s,`hello:{Y,Y}`, `X`); assert(s == `{X,X}`);. But this is lengthy and seems to lack additional assert checks. It's a little wordy but it has one line per things it is checking. And adjusting it to give more asserts is trivial. Until then, broken unit tests pass... Spot on. The unittest is broken. Not the thing it's testing and not foreach. -- ... IXOYE
Re: associative arrays: to sort or not to sort?
the correct solution is to make the check order independent. For example: string s = CallReturningJSON(); s = replace(s,`a:23.54`, `X`); s = replace(s,`b:0.0012`, `X`); s = replace(s,`{nested:{X,X}}`, `X`); s = replace(s,`goodbye:[true,or,false,[test,42,X]]`, `X`); s = replace(s,`array:[12,null,{}]`, `Y`); s = replace(s,is\n\ngreat, `Z`); s = replace(s,`json:Z`, `Y`); s = replace(s,`hello:{Y,Y}`, `X`); assert(s == `{X,X}`);. But this is lengthy and seems to lack additional assert checks. It's a little wordy but it has one line per things it is checking. And adjusting it to give more asserts is trivial. The order of name/value pairs in JSON objects is as unspecified as the order of foreach iteration for associative arrays. So, agreed, you would have to unittest a serialization against all permutations. But then, JSON has a jew more unspecified gaps like whitespace can be inserted between any pair of tokens. Shall we rely on the fact that the implementation currently does not insert whitespace between tokens? This would work for the unittest of std.json, but what's with the unittest of an implementation using std.json? Or, shall we implement a tokenizer in the unittest to get rid of extra whitespace between tokens? Until then, broken unit tests pass... Spot on. The unittest is broken. Not the thing it's testing and not foreach. Maybe, the thing under test is not broken. But there seems to be something wrong with the thing when it forces you to examine the unspecified result of toString in a unittest. I mean, it would have been easy for the author of the code to provide toCanonicalJSON, and a lot easier for users of the code. And, of course, foreach is not broken. But D removes a lot of unspecified gaps that make life hard in C or C++. And you have to provide opCmp in order to put your own keys into an associative array, so why don't you get them out in order? However, let's get things done: can the attached unittest be an acceptatble replacement for the broken one of std.json? begin 644 json-unittest.d M=6YI='1EW0@PH@(`...@+r\@06X@;W9EFQY('-I;7!L92!T97-T('-U:71E M+!I9B!I=!C86X@%Rv...@82!s97)I86QIF5D('-TFEN9R!A;F0*(`@ M(\O('1h...@=7-e('1H92!R97-U;'1I;F@=F%L=65S('1r...@=\...@9v5n M97)A=4...@86x@:61E;G1I8V%LB`@(`O+R!S97)I86QIF%T:6]N+!B;W1H M('1H92!D96-O95R(%N9!E;F-O95R('=Of...@h*(`@($I33TY686QU M92!V86QU93L*(`@('-TFEN9R!JV]N.PH@(`@B`@(!V86QU92`]('!A MG-E2E-/3BA@;G5L;`I+!AW-EG0H=]*4T].*9V86QU92D@/3...@8YU M;q...@*3l*(`@('9A;'5E(#T@%RV5*4T].*!TG5E8DL(%SV5R=AT M;TI33TXH)G9A;'5E*2`]/2...@=')U96`I.PH@(`...@=f%l=64@/2!P87)S94I3 M3TXH89A;'-E8DL(%SV5R=AT;TI33TXH)G9A;'5E*2`]/2...@9f%lV5@ M*3L*(`@('9A;'5E(#T@%RV5*4T].*`P8DL(%SV5R=AT;TI33TXH M)G9A;'5E*2`]/2!@,`I.PH@(`...@=f%l=64@/2!P87)S94I33TXH8#$R,V`I M+!AW-EG0H=]*4T].*9V86QU92D@/3...@8#$r,V`I.PH@(`...@=f%l=64@ M/2!P87)S94I33TXH8TT,S(Q8DL(%SV5R=AT;TI33TXH)G9A;'5E*2`] M/2...@+30s,c...@*3l*(`@('9A;'5E(#T@%RV5*4T].*`P+C(S8DL(%S MV5R=AT;TI33TXH)G9A;'5E*2`]/2!@,XR,V`I.PH@(`...@=f%l=64@/2!P M87)S94I33TXH8TP+C(S8DL(%SV5R=AT;TI33TXH)G9A;'5E*2`]/2!@ M+3`N,c...@*3l*(`@('9A;'5E(#T@%RV5*4T].*!N=6QL8DL(%SV5R M=AT;TI33TXH)G9A;'5E*2`]/2!@;G5L;`I.PH@(`...@=f%l=64@/2!P87)S M94I33TXH8(B8DL(%SV5R=AT;TI33TXH)G9A;'5E*2`]/2!@(B)@*3L* M(`@('9A;'5E(#T@%RV5*4T].*`Q+C(R,V4K,c...@*2p@87-S97)T*'1O M2E-/3...@f=f%l=64i(#T](`Q+C(R,V4K,c...@*3l*(`@('9A;'5E(#T@%R MV5*4T].*`B:5L;];G=OFQD(F`I+!AW-EG0H=]*4T].*9V86QU M92D@/3...@8)H96QL;UQN=V]R;0B8D[B`@(!V86QU92`]('!AG-E2E-/ M3BA@(EPB7%Q+UQB79;EQR7'0B8DL(%SV5R=AT;TI33TXH)G9A;'5E M*2`]/2!@(EPB7%Q+UQB79;EQR7'0B8D[B`@(!V86QU92`]('!AG-E M2E-/3...@6uu@*...@87-s97)T*'1O2E-/3...@f=f%l=64i(#T](!;76`I.PH@ M(`...@=f%l=64@/2!P87)S94I33TXH8%LQ,BPB9F]O(BQTG5E+9A;'-E76`I M+!AW-EG0H=]*4T].*9V86QU92D@/3...@8%lq,BPB9F]O(BQTG5E+9A M;'-E76`I.PH@(`...@=f%l=64@/2!P87)S94I33TXH8'M]8DL(%SV5R=AT M;TI33TXH)G9A;'5E*2`]/2!@w...@*3l*(`@('9A;'5E(#T@%RV5*4T]. M*![(F$B.C$L(F(B.FYU;Q]8D[@H@(`@:G-O;B`]('1O2E-/3...@f=f%l m=64i...@+r\@;W)D97(@;V8@;F%M92]V86QU92!P86ERR!I;B!*4T].(]B M:F5C=',@:7,@=6YS5C:69I960*(`@(%SV5R=AJV]N(#T](![(F$B M.C$L(F(B.FYU;Q]8!\?!JV]N(#T](![(F(B.FYU;PL(F$B.C%]8D[ M@H@(`...@=f%l=64@/2!P87)S94I33TXH8'LB:5L;\B.GLB:G-O;B(Z(FES M(=R96%T(BPB87)R87DB.ELQ,BQN=6QL+'M]77TL8`H@(`@(`@(`@(`@ M(`@(`@(`...@8)G;V]D8GEE(CI;=')U92PB;W(B+9A;'-E+%LB=5S=(L M-#(LR)N97-T960B.GLB82(Z,C,N-30L(F(B.C`N,#`Q,GU]75U]8D[B`@ M(!JV]N(#...@=]*4T].*9V86QU92D[(`O+R!OF1EB!O9B!N86UE+W9A M;'5E('!A:7)S(EN($I33TX@;V)J96-TR!IR!U;G-P96-I9FEE9`H@(`@ M87-S97)T*EN95X3V8H:G-O;b...@8'LB:G-O;B(Z(FES(=R96%T(BPB87)R M87DB.ELQ,BQN=6QL+'m]...@*2`a/2`M,2!\?`H@(`@(`@(`@(EN95X M3V8H:G-O;b...@8'LB87)R87DB.ELQ,BQN=6QL+'M]72PB:G-O;B(Z(FES(=R M96%T(g...@*2`a/2`M,2D[B`@(!JV]N(#T@F5P;%C92AJV]N+!@R)J MV]N(CHB:7,@9W)E870B+)AG)A2(Z6S$R+YU;PLWU=?6`L(![(F%R MF%Y(CI;,3(L;G5L;Q[?5TL(FIS;VXB.B)IR!GF5A=)]8D[B`@(!A MW-EG0H:6YD97A/9BAJV]N+!@R)A(CHR,RXU-PB8B(Z,XP,#$R?6`I M($](TQ('Q\B`@(`@(`@(`@:6YD97A/9BAJV]N+!@R)B(CHP+C`P M,3(L(F$B.C(S+C4T?6`I($](TQ*3L*(`@(!JV]N(#T@F5P;%C92AJ
Re: associative arrays: to sort or not to sort?
Hello Mario, But then, JSON has a jew more unspecified gaps like whitespace can be inserted between any pair of tokens. That can be dealt with by just being consistent. Shall we rely on the fact that the implementation currently does not insert whitespace between tokens? On the output side, why not? The unit test is for this implementation after all. And you have to provide opCmp in order to put your own keys into an associative array, so why don't you get them out in order? That's because AA's use closed hashing with tree used to deal with col3sions. However, let's get things done: can the attached unittest be an acceptatble replacement for the broken one of std.json? Move line 35 and 38 up one place each and you can drop the check for permutations. -- ... IXOYE
Re: associative arrays: to sort or not to sort?
Unless JSON requiers that the keys be in some order, No, JSON does not require the names of an object to be in alphabetical order. the correct solution is to make the check order independent. For example: string s = CallReturningJSON(); s = replace(s,`a:23.54`, `X`); s = replace(s,`b:0.0012`, `X`); s = replace(s,`{nested:{X,X}}`, `X`); s = replace(s,`goodbye:[true,or,false,[test,42,X]]`, `X`); s = replace(s,`array:[12,null,{}]`, `Y`); s = replace(s,is\n\ngreat, `Z`); s = replace(s,`json:Z`, `Y`); s = replace(s,`hello:{Y,Y}`, `X`); assert(s == `{X,X}`);. But this is lengthy and seems to lack additional assert checks. One way out could be to avoid real-world examples in the unittest. For the simple example of std.json that is only broken in theory, the correct solution could be: assert(s == `{a:1,b:null}` || s == `{b:null,a:1}`) But now assume, I want to implement a JSON-RPC encoder that uses std.json. A JSON-RPC request object has up to four name/value pairs (jsonrpc, method, params, id). Instead of only 2!, I now have 4! (too many) possible orders to check in the unittest of the JSON-RPC encoder. The unspecified order of the foreach iteration does not only affect the unittest of std.json, but also leaks out to far away implementations using std.json. The same is true for std.xml: assert(s == `tag goodbye=1 hello=0/`); may pass today, but is broken in theory! You have to notice that XML attributes are stored in an associative array and that toString is implemented using foreach. Until then, broken unit tests pass... This is a problem, isn't it?
Re: associative arrays: to sort or not to sort?
Hello Mario, That is, shall we produce canonical JSON text at the price of efficiency. Or, shall the perfect implementation of JSON objects as associative arrays be dropped? Or, what else? Unless JSON requiers that the keys be in some order, the correct solution is to make the check order independent. For example: string s = CallReturningJSON(); s = replace(s,`a:23.54`, `X`); s = replace(s,`b:0.0012`, `X`); s = replace(s,`{nested:{X,X}}`, `X`); s = replace(s,`goodbye:[true,or,false,[test,42,X]]`, `X`); s = replace(s,`array:[12,null,{}]`, `Y`); s = replace(s,is\n\ngreat, `Z`); s = replace(s,`json:Z`, `Y`); s = replace(s,`hello:{Y,Y}`, `X`); assert(s == `{X,X}`);. -- ... IXOYE
Re: associative arrays with arrays as value
MLT: Why is that? I think this is the right syntax (I am using Phobos on D1): import std.stdio: writefln; void main() { int[5][string] aa = [a: [1, 2, 3, 4, 5]]; aa[b][] = aa[a]; # line 5 writefln(aa); } But it gives an: Error: ArrayBoundsError temp(5) It looks like a bug. Static arrays will need to be improved in D, they have lot of bugs/limits. Note that in the current D there's a way to walk around that problem, you can wrap your static array into a struct. Here I use my Record (from my dlibs) that defines on the fly a struct that has several smart methods, among them there are opEquals, onHash, opCmp, toString, etc: http://www.fantascienza.net/leonardo/so/libs_d.zip import std.stdio: writefln; import d.templates: Record; import d.string: putr; alias Record!(int[5]) R; void main() { R[string] aa = [a: R([1, 2, 3, 4, 5])]; aa[b] = aa[a]; writefln(aa); putr(aa); } This works, and prints: [a:record([1, 2, 3, 4, 5]),b:record([1, 2, 3, 4, 5])] [a: record([1, 2, 3, 4, 5]), b: record([1, 2, 3, 4, 5])] Bye, bearophile