digitalmars.D.learn - Initalizing complex array types or some other problem ;/
- Prudence (114/114) Sep 15 2015 How does one initialize a tuple type and are arrays initialized
- anonymous (30/31) Sep 15 2015 Please be more specific in how it doesn't work. Mention the error messag...
- Prudence (197/228) Sep 15 2015 Maybe. Seems to work without it. The code below should compile on
- anonymous (2/4) Sep 15 2015 kthxbye
- Andrea Fontana (2/11) Sep 16 2015 "Prudence" seems not to fit well as nickname.
How does one initialize a tuple type and are arrays initialized by default? The code below doesn't work. I recently converted to use a tuple and that seemed to have broke it and I don't know why, when I changed the New function to use a ref, that made it worse cause now the array is all ways null. Debugging doesn't help much because, for some reason, VD won't show object information inside the mixin ObjectStore. alias StoreType = Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey]; public static StoreType Store; I thought using the alias would help but it doesn't. Trying to init it in the static this doesn't seem to help me, as I can't get it to new propertly. e.g., new StoreType(); fails. Any ideas? import std.stdio; import std.concurrency; extern (C) int getch(); import std.string; import std.concurrency; import core.time; import core.thread; import std.container.array; import std.typecons; public class SingleStore(TKey, TValue) { public TValue Value; public TKey Key; public Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey] Store; public auto Remove() { import std.algorithm; if (Value == null || Key == null) return; int count = 0; for(int i = 0; i < Store[Key].length; i++) { if (Store[Key][i][0] == Value && Store[Key][i][1] == this) { count++; Store[Key][i] = tuple(null, null); swap(Store[Key][i], Store[Key][max(0, Store[Key].length - count)]); i = i - 1; } } if (count == 1 && Store[Key].length == 1) { Store[Key] = null; Store.remove(Key); } else //Store[Key] = Store[Key][0..max(0,Store[Key].length-count)]; Store[Key].length = Store[Key].length - count; Value = null; Key = null; } public static auto New(TKey k, TValue v, ref Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey] s) { auto o = new SingleStore!(TKey, TValue)(k, v); // GC o.Store = s; return o; } private this(TKey k, TValue v) { Key = k; Value = v; } } // Creates a static Associative Array that stores multiple values per key. The object returned by New can then be used to remove the key/value without having to remember them specifically. public mixin template ObjectStore(TKey, TValue) { alias StoreType = Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey]; public static StoreType Store; public static auto New(TKey k, TValue v) { auto r = SingleStore!(TKey, TValue).New(k, v, Store); return r; } } alias dg = int delegate(int); class MyStore { mixin ObjectStore!(string, dg); } void main() { auto k = "x"; dg d1 = (int x) { return x; }; dg d2 = (int x) { return x; }; dg d3 = d1; dg d4 = (int x) { return 3*x; }; auto s = MyStore.New(k, d1); writeln(MyStore.Store[k].length); auto s1 = MyStore.New(k, d2); writeln(MyStore.Store[k].length); auto s2 = MyStore.New(k, d3); writeln(MyStore.Store[k].length); auto s3 = MyStore.New(k, d4); writeln(MyStore.Store[k].length); s1.Remove(); writeln(MyStore.Store[k].length); s2.Remove(); writeln(MyStore.Store[k].length); s.Remove(); writeln(MyStore.Store[k].length); s3.Remove(); getch(); }
Sep 15 2015
On Tuesday 15 September 2015 22:09, Prudence wrote:The code below doesn't work.Please be more specific in how it doesn't work. Mention the error message if there is one, or say how the code behaves differently from what you'd expect. Trying to compile the code (after kicking getch out), I get this error: core.exception.RangeError test.d(103): Range violation Line 103 is: writeln(MyStore.Store[k].length); I can't find where you set Store[k]. Maybe you forgot that or deleted it accidentally? I made a guess and added this line in SingleStore.New: o.Store[k] ~= tuple(v, o); It still throws a range error with this. That's because associative arrays are a little weird, unfortunately. An AA is effectively initialized on the first assignment. So (with my addition) the first SingleStore.New call initializes the AA. But it only initializes o.Store, not the original variable s (i.e. ObjectStore.Store). s is left empty. Possible solutions/workarounds: * Append to s[k], then assign s to o.Store. * Initialize ObjectStore.Store in a static constructor: ---- static this() { Store[TKey.init] = []; Store.remove(TKey.init); } ---- Aside: I have no idea what you're doing there, but it looks pretty complicated, to the point that I'd guess that it's more complicated than necessary.
Sep 15 2015
On Tuesday, 15 September 2015 at 20:54:49 UTC, anonymous wrote:On Tuesday 15 September 2015 22:09, Prudence wrote:Maybe. Seems to work without it. The code below should compile on your system and work(and prints 1 2 3 4, 4 3 2 1). The getch is required on windows if I want to see the output, so I don't know why you even bothered mention replacing it. import std.stdio; import std.concurrency; extern (C) int getch(); import std.string; import std.concurrency; import core.time; import core.thread; import std.container.array; import std.typecons; public class SingleStore(TKey, TValue) { public TValue Value; public TKey Key; public Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey] Store; // Duplicate entries will be removed together as there is no way to distinguish them public auto Remove() { import std.algorithm; if (Value == null || Key == null) return; int count = 0; for(int i = 0; i < Store[Key].length; i++) { if (Store[Key][i][0] == Value && Store[Key][i][1] == this) { count++; Store[Key][i] = tuple(null, null); // Set to null to release any references if necessary swap(Store[Key][i], Store[Key][max(0, Store[Key].length - count)]); i = i - 1; } } if (count == 1 && Store[Key].length == 1) { Store[Key] = null; Store.remove(Key); } else //Store[Key] = Store[Key][0..max(0,Store[Key].length-count)]; Store[Key].length = Store[Key].length - count; Value = null; Key = null; } public static auto New(TKey k, TValue v, ref Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey] s) { auto o = new SingleStore!(TKey, TValue)(); // GC o.Key = k; o.Value = v; s[k] ~= tuple(v, o); o.Store = s; return o; } } // Creates a static Associative Array that stores multiple values per key. The object returned by New can then be used to remove the key/value without having to remember specifically them. public mixin template ObjectStore(TKey, TValue) { // The object store. It is static. Mixin the template into it's different types to create different types of stores. All objects of that type are then in the same store. public static Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey] Store; public static auto New(TKey k, TValue v) { auto r = SingleStore!(TKey, TValue).New(k, v, Store); return r; } } //alias dg = int delegate(int); alias dg = string; public class cMyStore(TKey, TValue) { //mixin ObjectStore!(string, dg); mixin ObjectStore!(string, string); } void main() { alias MyStore = cMyStore!(string, string); auto k = "x"; auto r = &MyStore.Store; /* dg d1 = (int x) { return x; }; dg d2 = (int x) { return x; }; dg d3 = d1; dg d4 = (int x) { return 3*x; }; */ dg d1 = "a1"; dg d2 = "a2"; dg d3 = "a3"; dg d4 = "a4"; auto s = MyStore.New(k, d1); writeln(MyStore.Store[k].length); auto s1 = MyStore.New(k, d2); writeln(MyStore.Store[k].length); auto s2 = MyStore.New(k, d3); writeln(MyStore.Store[k].length); auto s3 = MyStore.New(k, d4); writeln(MyStore.Store[k].length); //auto x = MyStore.Store[k][0](3); //writeln("-" ~ x); s1.Remove(); writeln(MyStore.Store[k].length); s2.Remove(); writeln(MyStore.Store[k].length); s.Remove(); writeln(MyStore.Store[k].length); s3.Remove(); getch(); } I went and cleaned it up and somehow the issue miraculously resolved itself. It must have been from using the static this and such. The code I pasted had a partial changes trying to get it to work in the first place.The code below doesn't work.Please be more specific in how it doesn't work. Mention the error message if there is one, or say how the code behaves differently from what you'd expect. Trying to compile the code (after kicking getch out), I get this error: core.exception.RangeError test.d(103): Range violation Line 103 is: writeln(MyStore.Store[k].length); I can't find where you set Store[k]. Maybe you forgot that or deleted it accidentally? I made a guess and added this line in SingleStore.New: o.Store[k] ~= tuple(v, o); It still throws a range error with this. That's because associative arrays are a little weird, unfortunately. An AA is effectively initialized on the first assignment. So (with my addition) the first SingleStore.New call initializes the AA. But it only initializes o.Store, not the original variable s (i.e. ObjectStore.Store). s is left empty. Possible solutions/workarounds: * Append to s[k], then assign s to o.Store. * Initialize ObjectStore.Store in a static constructor: ---- static this() { Store[TKey.init] = []; Store.remove(TKey.init); }Aside: I have no idea what you're doing there, but it looks pretty complicated, to the point that I'd guess that it's more complicated than necessary.In any case, Maybe you are not as smart as you think you are if you can't understand it? Maybe next time you shouldn't assume you are the oracle of all knowledge and if you can't understand it then it's bad/wrong. In fact, it's quite simple to understand for anyone with half a brain. Seriously. Don't guess. It's not that complex and it would take you 5 mins to understand if you wanted. No reason to try and through your ego in it. 1. AA's can't have multiple values added to a single key(except with tuple, which becomes bulky to use). Hence the ObjectStore is a store(a dictionary/AA) that allows one to store multiple values per key. e.g., Store["x"] ~= "y"; Store["x"] ~= "z"; Store["x"] ~= "q"; 2. Because we might store things like delegates/lambda's in the ObjectStore, or other elements(pointers), the values in the store under some key may not be unique. alias d = {int x} { return x; }; Store["x"] ~= d; Store["x"] ~= d; Store["x"] ~= d; Here we have 3 copies of the same element, but the Store allows non-unique values. Also, storing a delegate(or any value) requires us to "remember" it if we ever want to remove it from the store(else how could we know which one to remove?). 3. Hence, SingleStore wraps the value and in a Singleton(more or less). When a SingleStore is created(should never be by a user), it keeps the key, the value inside it(so we don't have to). The user then keeps around the SingeStore(much easier than a delegate) and can remove it from the ObjectStore easily(s.remove()). It is sort of like a momento. 4. But because we have to worry about uniqueness, we store the values as tuples, the actual value and the SingleStore the value is associated with. Since there should be a one to one correspondence. If the value is not unique the SingleStore will be, which we use as a way to disambiguate values that look the same. e.g., what's kinda going on is Store["x"] ~= tuple(d, uniqueId1); Store["x"] ~= tuple(d, uniqueId2); Store["x"] ~= tuple(d, uniqueId3); Now, regardless if d is unique, the uniqueId's are unique(as they are just the ptr's to the different SingleStores that are created... and they all have different addresses). 5. So, as you can see, it's pretty easy. ObjectStore is just a store of objects by a key. It allows for multiple values and each value is unique. It also makes removing the values easy(not as easy for simple types but easier for complex types like delegates). 6. Sure there maybe a better way. That isn't the point. I've done this several times before in .NET and it takes about 5 mins. In D it has taken 2 days or so(well, only a few hours of work but still way to long). Partly because D's error messages are crap, Partly because I'm just getting back into D, and partly because Visual D doesn't show those static variables which makes it hard to know what's going on when debugging(since the ObjectStore is static, VD won't display whats going on with it). I'm still unsure if the code is safe(I'll have to add checks and all that) as I do not allocate the value array(every value in the AA is really an [] of tuples), yet I don't allocate anything(not the AA, not the [], or the tuple). Seems to work, maybe cause I'm doing s[k] ~= tuple(v, o); and ~ does the allocation for [] just like it does for the AA array? The reason for the mixin should be obvious. It allows one to create different ObjectStores(since static AA's are used, we have to use them in different classes. In heritence would just create one global store, which is probably not what one wants. Obviously there are other ways but I like the one line code to create a new store(e.g., how MyStore looks).
Sep 15 2015
On Wednesday 16 September 2015 03:46, Prudence wrote:In any case, Maybe you are not as smart as you think you are if you can't understand it?kthxbye
Sep 15 2015
On Wednesday, 16 September 2015 at 01:46:09 UTC, Prudence wrote:In any case, Maybe you are not as smart as you think you are if you can't understand it? Maybe next time you shouldn't assume you are the oracle of all knowledge and if you can't understand it then it's bad/wrong. In fact, it's quite simple to understand for anyone with half a brain. Seriously. Don't guess. It's not that complex and it would take you 5 mins to understand if you wanted. No reason to try and through your ego in it."Prudence" seems not to fit well as nickname.
Sep 16 2015