Re: Initalizing complex array types or some other problem ;/
On Tuesday, 15 September 2015 at 20:54:49 UTC, anonymous wrote: 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); } 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 = /* 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);
Initalizing complex array types or some other problem ;/
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(); }
Convert array to tupled array easily?
I created the following code that some of you have already seen. It's sort of a multiple value AA array with self tracking. The problem is, that for some type values, such as delegates, the comparison is is identical. (basically when the delegate is the same) To solve that problem, I'd like to try and turn the Value into Tuples of the Value and the address of the SingleStore wrapper(which should be unique). e.g., public Tuple!(TValue, void*)[][TKey] Store; then I'll simply compare the value and address stored with the this(inside single store) instead of just this. Of course, this requires somewhat of a rewrite of the code(trying it produced all kinds of errors(I tried to fix up all the references and correlated variables but still a mess, specially with D's error codes). It shouldn't be that much trouble though. Essentially where ever I access the value, I want to instead of use value from the tuple(a single indirection). Probably not that easy though? 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 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++) { auto c = Store[Key][i]; if (c == Value) { count++; Store[Key][i] = 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)]; Value = null; Key = null; } public static auto New(TKey k, TValue v, ref TValue[][TKey] s) { auto o = new SingleStore!(TKey, TValue)(k, v); 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 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 TValue[][TKey] Store; public static auto New(TKey k, TValue v) { (Store[k]) ~= v; auto o = SingleStore!(TKey, TValue).New(k, v, Store); return o; } public string ToString() { return "asdf"; } } alias dg = int delegate(int); //alias dg = string; class MyStore { mixin ObjectStore!(string, dg); //mixin ObjectStore!(string, string); } 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; }; /* 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(); }
Re: shared array?
On Sunday, 13 September 2015 at 16:58:22 UTC, Ola Fosheim Grøstad wrote: On Sunday, 13 September 2015 at 15:35:07 UTC, Jonathan M Davis wrote: the GC heavily. And the reality of the matter is that the vast majority of programs will have _no_ problems with using the GC so long as they don't use it heavily. Programming like you're in Java and allocating everything on the heap will kill performance, but idiomatic D code doesn't do that, and Phobos doesn't do that. Far too many programmers freak out at the thought of D even having a GC and overreact thinking that they have to root it out completely, when there really is no need to. Plenty of folks how written highly performant code in D using the GC. You just have to avoid doing a lot of allocating and make sure you track down unwanted allocations when you have a performance problem. I don't understand this argument. Even if the GC heap only contains a single live object, you still have to scan ALL memory that contains pointers. So how does programming like you do in Java affect anything related to the GC? Or are you saying that finalization is taking up most of the time? The problem is that these people arguing that the GC is the holy grail simply use statistics for their reasoning. They pigeon everyone in the same box they exist in, and you find out it's useless to argue with them because their logic is flawed. What if I happen to write a RT app that happens to use a part of phobo's that happens to heavily rely on the GC? Am I suppose to use -vgs all the time to avoid that? Do I avoid phobo's because 3 functions in it use the GC? Am I suppose to memorize a table of all the places phobo's uses the GC and then roll my own to avoid them? The fact is, that the proponents of the GC such as JMD do not write RT apps and could care less bout that aspect. This is why they make such easy claims. For them, RT is just theoretical mumbo jumbo that doesn't exist in the real world. The GC is, also, for them, a safety blanket so they can be lazy and not have to keep track of all the things they should be. This type of mentality seems to run rampet in the contributors of D. They simply cannot understand the perspective of the other side(or refuse to). Statistics has nothing to do with facts. The fact is, for a hard real time app, the GC and it's stop the world behavior is a no go. As long as the mentality exists that the GC is good enough because it 99% of phobo's doesn't use it or 99% of apps don't need RT, or whatever, D will never be as powerful as it can be. Basically, I know you need your snotty safety blanket and it works for you, but I don't want to use it! Don't force me! I won't force you to give up your blanket but don't force me to use it. The road goes both ways, stop trying to make it one way. (The argument is fundamentally different. They want to exclude, I want to include) Of course, the real issue is, that it will take someone that has the opposite point of view from them to actually do anything about it, because it's obvious they won't work the direction they think is a waste. So, ultimately, it's people like me that have to step up and actually do the work. I am hesitant because it's always an uphill battle with such people. Instead of working together, they have to make it a struggle. (it's always "Why are you trying to take my safety blanket away!!! wa, wa wa" and tears follow)
Re: shared array?
On Sunday, 13 September 2015 at 17:16:02 UTC, ponce wrote: On Sunday, 13 September 2015 at 17:00:30 UTC, Ola Fosheim Grøstad wrote: On Sunday, 13 September 2015 at 16:53:20 UTC, ponce wrote: GC is basically ok for anything soft-realtime, where you already spend a lot of time to go fast enough. And if you want hard-realtime, well you wouldn't want malloc either. It's a non-problem. If this was true then Go would not have a concurrent collector. I was speaking of the D language. Of course, that makes it make sense!
Re: Mixin templates accessing mixed out scope
On Saturday, 12 September 2015 at 17:11:04 UTC, anonymous wrote: On Saturday 12 September 2015 16:30, Ali Çehreli wrote: Reduced: [...] Error: type SingleStore is not an expression Reduced further: class MyStore { class SingleStore { static void New() // Removing 'static' compiles { new SingleStore(); } } } And now the problem can be spotted: SingleStore is a nested class. That means, instances of it are bound to MyStore instances. But New is static, so it doesn't have a MyStore to which it could attach the `new SingleStore`. That error message is pretty awful. I filed an issue: https://issues.dlang.org/show_bug.cgi?id=15049 like most D errors ;/ it's the #1 problem I'm struggling with in D. Remember there's another error with remove, that isn't releated to SingleStore. As for a fix: I guess SingleStore isn't supposed to be a nested class. Mark it static then. NO! That is the whole point! SingleStore is a momento that wraps the key value pair, e.g., auto t = DeleteStore.New("mycooldelegate", (int x) { return true; }); t is suppose to be a single store. then t.Remove(); removes the delegate from the store. Note I don't have to know the actual key or delegate!! Which is the whole point! Else it would lool like this: store[][string] mydelegatestore; auto dg = (int x) { return true; }; mydelegatestore["mycooldelegate"] ~= dg; then mydelegatestore["mycooldelegate"].remove(d => dg == d); which requires remembering both the key and the delegate, which makes using inline lambdas infeasible(because you'll never be able to remove them). I see no reason why SingleStore has to be static. The mixin template should insert all that stuff into the class, which, by the way, works... I've also used that New pattern all that time and it works, maybe not for nested classes. Moving SingleStore outside the template works. I've fixed the issue with that, it's not as pretty but works. Still have the remove error: 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 TValue[][TKey] Store; public auto Remove() { import std.algorithm; remove!(c => Value == c")(Store[this.Key], SwapStrategy.unstable); // Not working, can't disambiguate } public static auto New(TKey k, TValue v, ref TValue[][TKey] s) { auto o = new SingleStore!(TKey, TValue)(k, v); o.Store = s; return o; } private this(TKey k, TValue v) { Key = k; Value = v; } } public mixin template ObjectStore(TKey, TValue) { public static TValue[][TKey] store; public static auto New(TKey k, TValue v) { (store[k]) ~= v; auto o = SingleStore!(TKey, TValue).New(k, v, store); o.store = store; return o; } } class MyStore { mixin ObjectStore!(string, bool delegate(int)); } void main() { auto s = MyStore.New("x", (int x) { return true; }); // works, stores delegate in MyStore s.Remove(); // Doesn't work because std.algorithm's remove isn't working getch(); } (The whole point of nesting was so I wouldn't have to explicitly create a pointer to the store in SingleStore. Should have worked, probably another one of D's bugs)
Re: Mixin templates accessing mixed out scope
On Saturday, 12 September 2015 at 14:30:16 UTC, Ali Çehreli wrote: On 09/12/2015 06:37 AM, Prudence wrote: Says the creating new SingleStore is not an expression Reduced: mixin template ObjectStore(TKey) { class SingleStore { static void New()// Removing 'static' compiles { new SingleStore(); } } } class MyStore { mixin ObjectStore!(int); } void main() { auto s = new MyStore(); } Error: type SingleStore is not an expression Ali Are you saying this is a bug or something else? The only alternative I can think of is to use string mixins but this method should work?
Re: Better lambdas!!!!!!!!!!
On Saturday, 12 September 2015 at 10:44:05 UTC, Pierre Krafft wrote: On Saturday, 12 September 2015 at 03:32:51 UTC, Prudence wrote: On Saturday, 12 September 2015 at 02:13:11 UTC, Pierre Krafft wrote: On Saturday, 12 September 2015 at 01:03:54 UTC, Prudence wrote: On Thursday, 10 September 2015 at 18:02:36 UTC, Ali Çehreli wrote: On 09/10/2015 10:55 AM, Prudence wrote: > How bout this: > > void myfunc(double delegate(int i, int z, float f)) {} > > > myfunc((int i, int z, float f) { return i*z*f; } } > > vs > > myfunc({ return i*z*f; }) // Names of parameters are inferred from > signature. Considering other features of the language, that's pretty much impossible in D. What if there is another i in scope: int i; myfunc({ return i*z*f; }); Now, should it call another overload of myfunc that takes (int z, int f) because i is something else? Should the compiler analyze the body of the code and decide which symbols could be parameters? And then go through all overloads of myfunc? etc.? Ali As I said, it could throw a warning or error. It, in some sense, is already a a problem with nested blocks that hide outside variables, is it not? The compiler doesn't need to scan anything. It knows the which parameters from the definition! -> void myfunc(double delegate(int i, int z, float f)) <- Compiler knows to use the names here as the default names in for the parameters when. when used: myfunc({ return i*z*f; }); <- Oh, there are the names, we know what they are because the signature is tells us. The compiler does the following: 1. Sees we have a block without any parameters defined. i.e., a lambda. 2. It looks up the signature of myfunc to find out what the names are 3. It sees that they are i z and f 4. Now it knows and it effectively rewrites the code as myfunc((i,z,f) { return i*z*f; }); Surely this is not difficult, 4 steps? You're making your code more brittle for a small gain. The suggestion makes parameter usage order important and the compiler can't warn about my typos. Consider: myfunc({return "x:"~x~"y:"-y;}) getting changed to myfunc({return "y:"~y~"x:"~x;}); Or the typo in myfunc({return i*z+f*j;}); Lambdas are already very concise. This proposal doesn't give any benefits outside of very simple lambdas. Such lambdas are already so simple that they could use some standard functions instead (like sum, to!T, and bind). What does this have to do with my proposal? Those issues exist regardless of the simplification. myfunc({return "x:"~x~"y:"-y;}) getting changed to myfunc({return "y:"~y~"x:"~x;}); huh? What do you mean the suggestion makes parameter usage order important? They are important, it has nothing to do with the suggestion? Are you saying that you want to reserve the right to do something like myfunc(string delegate(string x, string y)); and myfunc((y,x){ "y:"~y~"x:"~x; }) ? If so, or unless I'm missing something, that's bad no matter what. Changing the order and reversing the names is more than just confusing, it's hard to read and most people will gloss over that fact. Be consistent with your parameters and maybe you'll have less bugs? Or the typo in myfunc({return i*z+f*j;}); Again, what does this have to do with anything? A typo is a typo and is always a mistake. The above example has the same effect regardless if the parameters are explicit or deduced. myfunc((i,z,f) {return i*z+f*j;}); j is still a problem. If j is defined outside the lambda then regardless of specific or implicit parameter names, it will not cause any problems. In either case, the compiler can see that j is either referenced outside the scope or undefined. It has nothing to do with the parameters used. Of course maybe I'm missing something, but essentially are not almost all uses of lambda's simply copying the parameter signature of the delegate. It already infers types... you could say that leads to typo's too... myfunc({return "x:"~x~"y:"-y;}); is infered to mean myfunc((x,y){return "x:"~x~"y:"-y;}); while myfunc({return "y:"~y~"x:"~x;}); is infered to mean myfunc((y,x){return "y:"~y~"x:"~x;}); which is not what I expect since the lambda I want is myfunc((x,y){return "y:"~y~"x:"~x;}); This can lead to subtle bugs which are very hard to see. In the typo example there could be two overloaded functions differing only in that one takes a delegate having 3 parameters and one taking a delegate having 4 parameters. If we explicitly write the lambda parameters the typo will be found since j is undefined. But when parameters are inferred the compiler will see that {return i*z + f*j;} matches the function taking a lambda with 4 parameters. Inferred parameter types are on the brink of what I can allow. They can risk typos, but not as easily since you write the parameters twice (declaration and usage). They can also silently change if the function taking the delegate has the parameter type changed. I don't want
Does a synchronization yield on waiting thread?
It would seem to be the logical thing to do? That is, suppose two threads are sharing a resource. Thread A has it locked. B is "waiting". Is B in a loop burning cycles running in the background(regardless of thread.sleep, which only alleviates the problem) or does it yield completely and somehow inform the lock to resume it when A has unlocked the resources? The first one burns cycles and can have timing problems. I.e., What if A locks and unlocks at the same rate that B checks? (I suppose a random sleep time would help with this) ( "Yielding", OTOH, has B burn no cycles waiting in a loop. This can lead to optimization and prioritization and all that(after an unlock, all the threads waiting can be called, but in what order). Obviously yielding is more complex and requires the threads kept track of(an array for each lock/unlock pair) but far more efficient. I'm hoping D does this, but not holding my breath.
Re: shared array?
On Saturday, 12 September 2015 at 06:23:12 UTC, Jonathan M Davis wrote: On Friday, September 11, 2015 23:29:05 Laeeth Isharc via Digitalmars-d-learn wrote: On Friday, 11 September 2015 at 21:58:28 UTC, Adam D. Ruppe wrote: > [...] Seems to be quite a lot of FUD wrt use of standard library and GC, which means also perhaps we don't communicate this point very well as a community. Making Phobos GC-optional perhaps is an ultimate answer. But people seem to think that you're back to C without the GC. Aside from the few classes in Phobos, its GC usage is almost entirely restricted to when it allocates arrays or when it has to allocate a closure for a delegate, which can happen in some cases when passing predicates to range-based algorithms. Avoiding functions that need to allocate arrays avoids that source of allocation, and using functors or function pointers as predicates avoids having to allocate closures. So, you _can_ end up with GC allocations accidentally in Phobos if you're not careful, but on the whole, the assertion that Phobos uses the GC heavily is FUD - or at least a misunderstanding. But as we make more of the functions use lazy ranges rather than arrays (particularly with regards to strings), and we make more of the code @nogc, it becomes even clearer that the GC isn't involved. Also, improvements to how lambdas are handled should reduce how often closures have to be allocated for them. I don't think it's that simple. Saying that it doesn't use it most of the time is not an answer/solution. Using it at all is a problem because one doesn't know when and where. I realize there is a switch now(-vgc), and maybe that is the solution, but you say "well, phobos only uses 0.01% on the GC", yet since you either don't, can't, or won't know where that is, then it might as well be 100% if you would like to potentially get off the GC one day. It's like playing Russian roulette. It doesn't matter if only 1/6 times will kill you. It's totally different than 0/6.
Mixin templates accessing mixed out scope
The following code simply does not work, it might be buggy now after fiddling with it but basically remove and the SingleStore.New are not working(Says the creating new SingleStore is not an expression, which makes no sense to me). Essentially I'm creating a mixin template so I can have different "object stores", which is just an associative array of arrays. The SingleStore wraps the key, value pair added to the store so that I can keep track of and remove the added object easily without having to explicitly remember everything(e.g., what if TValue is a delegate? Then it get's messy). Why remove can't disambiguate is beyond me... Why I can't create a SingleStore!(int, double)() is beyond me! It would be nice if D's errors were a little more helpful! Error Error: type SingleStore!(int, double) is not an expression Test.d 56 auto o = new SingleStore!(TKey, TValue)(k, v); huh??? Have I just lost it or is this how one is suppose to create such an object? (I do realize that I do not have to parameterize SingleStore. It is irrelevant here though) 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; // Creates a static Associative Array that stores multiple values per key. The object returned by New can then be used to remove the object without having to remember the object specifically. 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 TValue[][TKey] store; public static auto New(TKey k, TValue v) { (store[k]) ~= v; auto o = SingleStore!(TKey, TValue).New(k, v); return o; } public static auto Remove(SingleStore!(TKey, TValue) o) { import std.algorithm; //remove!(c => (this.Value == c))(store[o.Key], SwapStrategy.unstable); } public class SingleStore(TKey, TValue) { public TValue Value; public TKey Key; public auto Remove() { import std.algorithm; //remove!("c => (this.Value == c)")(store[this.Key], SwapStrategy.unstable); //super.Remove(this); } public static auto New(TKey k, TValue v) { auto o = new SingleStore!(TKey, TValue)(k, v); return o; } private this(TKey k, TValue v) { Key = k; Value = v; } } } class MyStore { mixin ObjectStore!(int, double); } void main() { auto s = new MyStore(); getch();
Re: shared array?
On Friday, 11 September 2015 at 16:04:22 UTC, Kagamin wrote: On Friday, 11 September 2015 at 14:54:00 UTC, Prudence wrote: But in this case it is static, so why does it matter? Do you have any ideas how to wrap it or fix this? It matters exactly because it is static. A code written for single-threaded environment may not work correctly in shared context. It simply wasn't written for it. The way to fix it is to write code for shared context. I don't care about "maybe" working. Since the array is hidden inside a class I can control who and how it is used and deal with the race conditions. What I want is to be able to use Array so I don't have to rely on the GC. but since it complains about the ~this destruction, how can I fix that? If I wrap Array, and use a non-shared array inside it, I'll still have the same problem because it will be thread local to the object? or is shared applied to all sub types of a class? e.g., class MySharedArrayWrapper { static Array!(int) a; } and instead I use static shared MySharedArrayWrapper; But a isn't marked shared, so will it be TLS, which put's me back at square one. Or it it marked shared, which then still complains? Again, I'm asking how, not why.
Re: shared array?
On Friday, 11 September 2015 at 19:27:49 UTC, Adam D. Ruppe wrote: On Friday, 11 September 2015 at 17:29:47 UTC, Prudence wrote: I don't care about "maybe" working. Since the array is hidden inside a class I can control who and how it is used and deal with the race conditions. You could use __gshared instead of shared. It means put it in non-tls storage, just like shared, but the compiler will not attempt to help you use it correctly; you're on your own for synchronization, etc. What I want is to be able to use Array so I don't have to rely on the GC. But, again, built-in slices do NOT rely on the GC. Only specific methods on them do and you can use your own implementation for them. Really? Can you back up this claim? Not saying your lying, I'd just like to know it's true for a fact? Ho wan you use "specific methods"? Do you mean I do not use new to allocate and use malloc(more or less)? In that case, am I not essentially just re-creating Array? Obviously I can write my own array type and I can even write my own compiler, but that's no that the point, is it?
Re: shared array?
On Friday, 11 September 2015 at 20:30:37 UTC, Adam D. Ruppe wrote: On Friday, 11 September 2015 at 20:06:53 UTC, Prudence wrote: Can you back up this claim? Not saying your lying, I'd just like to know it's true for a fact? The list of things that trigger the GC is pretty short. See the bottom of this page: http://dlang.org/garbage.html Basically, the three things that can do a gc allocation in a built in array are: increasing the length, the ~= and ~ operators, and the [a,b,c] literal syntax. Slicing, indexing, etc, the other basic operations do not. If you do: ubyte[] a = (cast(ubyte*) malloc(4)[0..4];, it will compile... and create a slice from the malloced memory. That's one way to create an array without GCing it. In that case, am I not essentially just re-creating Array? Array does a lot of other stuff too... you only really need append and maybe shrink for a static variable, since tracking ownership doesn't matter (it is never disappearing since it is global) Oh really?!?! I thought slicing used the GC? Is this a recent development or always been that way? ok, so if I just use a shared [], and create it using malloc(as you've done above) then release and remalloc when I need to append(not efficient but ok in my senario), then it won't use the GC? If so, then I can handle that! I guess [] doesn't have a capacity field so I'll have to keep track of that. Other wise, it should be pretty simple. Of course, I still feel like I'm trying to implement array because everything turns in to "lots of stuff" at some point ;/
Multidimension AA's and remove
Error: template std.algorithm.mutation.remove cannot deduce function from argument types !()(bool delegate(void*, uint, uint, int)[], void), candidates are: std.algorithm.mutation.remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range, Offset offset) if (s != SwapStrategy.stable && isBidirectionalRange!Range && hasLvalueElements!Range && hasLength!Range && Offset.length >= 1) std.algorithm.mutation.remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range, Offset offset) if (s == SwapStrategy.stable && isBidirectionalRange!Range && hasLvalueElements!Range && Offset.length >= 1) std.algorithm.mutation.remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range range) if (isBidirectionalRange!Range && hasLvalueElements!Range) coming from static TValue[][TKey] s; (s[key]).remove(c => value == c); How to disambiguate or do what I'm trying to do: I'm trying to create an associative array with multiple values per key. Hence the AA with an extra dynamic array on it. I've tried TValue[TKey][] s; and other stuff without success(essentially same error about not being able to deduce remove) I would expect (s[key]) to return the normal array. I've tried this too. remove!(c => this.Value == c)(store[this.Key], SwapStrategy.unstable); At the very least: Is T[][S] an associative array with keys of type S and values of an array of type T or is it backwards? Also, how to disabmiguate Thanks.
Re: Better lambdas!!!!!!!!!!
On Thursday, 10 September 2015 at 18:02:36 UTC, Ali Çehreli wrote: On 09/10/2015 10:55 AM, Prudence wrote: > How bout this: > > void myfunc(double delegate(int i, int z, float f)) {} > > > myfunc((int i, int z, float f) { return i*z*f; } } > > vs > > myfunc({ return i*z*f; }) // Names of parameters are inferred from > signature. Considering other features of the language, that's pretty much impossible in D. What if there is another i in scope: int i; myfunc({ return i*z*f; }); Now, should it call another overload of myfunc that takes (int z, int f) because i is something else? Should the compiler analyze the body of the code and decide which symbols could be parameters? And then go through all overloads of myfunc? etc.? Ali As I said, it could throw a warning or error. It, in some sense, is already a a problem with nested blocks that hide outside variables, is it not? The compiler doesn't need to scan anything. It knows the which parameters from the definition! -> void myfunc(double delegate(int i, int z, float f)) <- Compiler knows to use the names here as the default names in for the parameters when. when used: myfunc({ return i*z*f; }); <- Oh, there are the names, we know what they are because the signature is tells us. The compiler does the following: 1. Sees we have a block without any parameters defined. i.e., a lambda. 2. It looks up the signature of myfunc to find out what the names are 3. It sees that they are i z and f 4. Now it knows and it effectively rewrites the code as myfunc((i,z,f) { return i*z*f; }); Surely this is not difficult, 4 steps?
Re: Better lambdas!!!!!!!!!!
On Saturday, 12 September 2015 at 02:13:11 UTC, Pierre Krafft wrote: On Saturday, 12 September 2015 at 01:03:54 UTC, Prudence wrote: On Thursday, 10 September 2015 at 18:02:36 UTC, Ali Çehreli wrote: On 09/10/2015 10:55 AM, Prudence wrote: > How bout this: > > void myfunc(double delegate(int i, int z, float f)) {} > > > myfunc((int i, int z, float f) { return i*z*f; } } > > vs > > myfunc({ return i*z*f; }) // Names of parameters are inferred from > signature. Considering other features of the language, that's pretty much impossible in D. What if there is another i in scope: int i; myfunc({ return i*z*f; }); Now, should it call another overload of myfunc that takes (int z, int f) because i is something else? Should the compiler analyze the body of the code and decide which symbols could be parameters? And then go through all overloads of myfunc? etc.? Ali As I said, it could throw a warning or error. It, in some sense, is already a a problem with nested blocks that hide outside variables, is it not? The compiler doesn't need to scan anything. It knows the which parameters from the definition! -> void myfunc(double delegate(int i, int z, float f)) <- Compiler knows to use the names here as the default names in for the parameters when. when used: myfunc({ return i*z*f; }); <- Oh, there are the names, we know what they are because the signature is tells us. The compiler does the following: 1. Sees we have a block without any parameters defined. i.e., a lambda. 2. It looks up the signature of myfunc to find out what the names are 3. It sees that they are i z and f 4. Now it knows and it effectively rewrites the code as myfunc((i,z,f) { return i*z*f; }); Surely this is not difficult, 4 steps? You're making your code more brittle for a small gain. The suggestion makes parameter usage order important and the compiler can't warn about my typos. Consider: myfunc({return "x:"~x~"y:"-y;}) getting changed to myfunc({return "y:"~y~"x:"~x;}); Or the typo in myfunc({return i*z+f*j;}); Lambdas are already very concise. This proposal doesn't give any benefits outside of very simple lambdas. Such lambdas are already so simple that they could use some standard functions instead (like sum, to!T, and bind). What does this have to do with my proposal? Those issues exist regardless of the simplification. myfunc({return "x:"~x~"y:"-y;}) getting changed to myfunc({return "y:"~y~"x:"~x;}); huh? What do you mean the suggestion makes parameter usage order important? They are important, it has nothing to do with the suggestion? Are you saying that you want to reserve the right to do something like myfunc(string delegate(string x, string y)); and myfunc((y,x){ "y:"~y~"x:"~x; }) ? If so, or unless I'm missing something, that's bad no matter what. Changing the order and reversing the names is more than just confusing, it's hard to read and most people will gloss over that fact. Be consistent with your parameters and maybe you'll have less bugs? Or the typo in myfunc({return i*z+f*j;}); Again, what does this have to do with anything? A typo is a typo and is always a mistake. The above example has the same effect regardless if the parameters are explicit or deduced. myfunc((i,z,f) {return i*z+f*j;}); j is still a problem. If j is defined outside the lambda then regardless of specific or implicit parameter names, it will not cause any problems. In either case, the compiler can see that j is either referenced outside the scope or undefined. It has nothing to do with the parameters used. Of course maybe I'm missing something, but essentially are not almost all uses of lambda's simply copying the parameter signature of the delegate. It already infers types... you could say that leads to typo's too...
Re: shared array?
On Friday, 11 September 2015 at 13:12:14 UTC, Adam D. Ruppe wrote: On Friday, 11 September 2015 at 04:28:52 UTC, Prudence wrote: I thought about that but then I have to rely on the GC for some simple things. Doesn't seem like the right way to go. Since it is static, it will never be collected anyway, so you could just use it and it'll work for convenience and probably lose nothing, or very trivially write an append function that uses any scheme you want instead of doing ~= on it without even worrying about freeing it. And that makes it worse!! If it's never collected and the GC scans it every time, it means it adds a constant overhead to the GC for absolutely no reason, right? It also then makes every dependency on it GC dependent(@nogc can't be used)? It just seems like it's the wrong way to go about it.
Re: shared array?
On Friday, 11 September 2015 at 07:41:10 UTC, Kagamin wrote: I get only one error: Error: non-shared method std.container.array.Array!(void delegate()).Array.~this is not callable using a shared object. It will try to destruct the array on program termination, but it requires the destructor to be aware of the shared context. But in this case it is static, so why does it matter? Do you have any ideas how to wrap it or fix this?
Better lambdas!!!!!!!!!!
How bout this: void myfunc(double delegate(int i, int z, float f)) {} myfunc((int i, int z, float f) { return i*z*f; } } vs myfunc({ return i*z*f; }) // Names of parameters are inferred from signature. by specifying the parameter names in the signature, we don't have to specify them in the lamba creation. This doesn't replace the original way, just adds the ability to infer the names if they are not specified. Of course, this hides the names outside the lambda, but a warning could be issued(no different than if one does it explicitly.
Version for windows/console compilation?
Is there a flag for knowing when a project is compiling for windows(Uses WinMain) vs a console(normal main)? version(Windows) is always valid for a console app, so it is useless to disambiguate between a console app and a windows app. (Say I have both a main and a winmain in my code, I need to select between them(it's a bit more complex than this but)).
shared array?
I can't create a shared array: static Array!(bool delegate(int, WPARAM, LPARAM)) callbacks; (prepending shared produce a ton of errors with the Array class) I've tried making it a pointer and other things. The array must be static and must be shared. Without shared everything works but I don't get, obviously, a useful array(it's empty because all the updating goes on in the main thread). 1. How do I create a shared array? 2. Why prepending shared produces any problems? I thought shared simply made a variable global to all threads?
Re: Version for windows/console compilation?
On Friday, 11 September 2015 at 01:36:31 UTC, Mike Parker wrote: On Thursday, 10 September 2015 at 18:10:43 UTC, Adam D. Ruppe wrote: BTW it is pretty rare that you should actually write a WinMain in D. The right thing to do in most cases is to write a normal main function. You can still get the windows gui subsystem with a linker flag. Specifically, add the following when using the Microsoft linker (compiling with -m64 or -m32mscoff): -L/SUBSYSTEM:windows,6.00 -L/ENTRY:mainCRTStartup And this when using OPTLINK: -L/SUBSYSTEM:windows,5.01 The version numbers are optional. I use 6.00 with the MS linker because it covers both 32-bit and 64-bit apps on Vista and later, and is the default for the VS 2015 linker. [1] https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx I don't think I've written a WinMain in D in 10 years. I'm using Visual D and I assume it takes care of all this. It works so that's not a huge problem. I'm simply creating my own version flags in VD properties. Not the best way because I'll have to remember to set the flags every time I use the library or I'll get errors about stuff missing. I was hoping D had a flag to disambiguate console and windows apps(or some type to CT way to check).
Re: shared array?
On Friday, 11 September 2015 at 00:50:15 UTC, Adam D. Ruppe wrote: On Friday, 11 September 2015 at 00:48:28 UTC, Prudence wrote: static Array!(bool delegate(int, WPARAM, LPARAM)) callbacks; Try just using a regular array instead of the library Array. static bool delegate(int, WPARAM, LPARAM)[] callbacks; my guess is the Array library thing isn't marked as shared internally. I thought about that but then I have to rely on the GC for some simple things. Doesn't seem like the right way to go.
Re: Member function pointers
On Tuesday, 27 May 2014 at 12:21:40 UTC, d coder wrote: https://github.com/D-Programming-Language/dmd/pull/3181 Daniel asked me to use this. And it works. Use something like: union U { void delegate(int) dg; struct { void* ptr; void function(int) funcptr; } } U u; u.dg = dg; u.funcptr = ...; u.ptr = ...; Regards - Puneet What's the current state of this? I'm in need of such behavior for win32 interop. I'm thinking that one can make the above code more general by using it in a mixin and automatically generating the funcptr signature: import std.stdio; import std.concurrency; extern (C) int getch(); import std.string; template FancyDelegate(O, D) { const char[] FancyDelegate = "union "~O.stringof~"Delegate { "~D.stringof~" dg; struct { "~O.stringof~"* ptr; "~D.stringof.replace("delegate(", "function("~O.stringof~",").replace(",)", ")")~" funcptr; } }"; //const char[] FancyDelegate = "union "~O.stringof~"Delegate { "~D.stringof~" dg; struct { "~O.stringof~"* ptr; "~D.stringof.replace("delegate(", "function(")~" funcptr; } }"; } class X { public int z = 2; public void foo(int x) { //writeln(this.z*x); writeln(x); } } void delegate(int) dg; mixin(FancyDelegate!(X, typeof(dg))); void main() { auto xX = new X(); XDelegate x; x.dg = //x.dg(3); x.ptr = x.funcptr(xX, 5); //x.funcptr(5); getch(); } Unfortunately this fails when entering the function. I've tried various things(passing , etc..., passing nothing(the comments, etc.) I thought a delegate, when called, was called like a member function? It seems that a delegate is some magic black box that we can't emulate in any way shape or form due to the calling conventions used?
Concurency wtf?
I can't seem to receive certain messages, my code is very simple and it all works except for receiving: in one thread I do locate("MyMonitor").send(cast(shared)pt); which sends the message(pt is a windows POINT structure). In the MyMonitor spawned thread, I have while (true) { POINT y; receiveTimeout(100.msecs, (POINT p) { y = p; } ); Thread.sleep(100.msecs); continue; } Note that everything works except the matching in receiveTimeout. (I've tired various things and simplifications to no avail). I can send simple types like int and bool. e.g., sending a literal works fine. My guess is the shared is causing problems but I've tried all common sense combinations. But I have to send shared, else send complains about sending unshared types. Of course, the great thing is, all examples use literals and hence not real world examples(isn't that nice?). Please don't ask me to provide source. The issue has nothing to do with the other code but specifically the TYPE that is being sent. Works for some types and not others. It is almost surely due to the shared issue, any ideas?
Win32 function vs delegate issues with api
I have hook = SetWindowsHookEx(WH_MOUSE, , NULL, ThreadID); Proc is the standard hook proc: public extern (Windows) LRESULT Proc(int code, WPARAM wParam, LPARAM lParam) I get a type mismatch because Proc is a delegate and SetWindowsHookEx expects a function. Making proc static works but not the behavior I want since all this stuff is wrapped in a class. Is there any way to pass Proc to SetWindowsHookEx without issues of GB and such? Error: function windows.winuser.SetWindowsHookExA (int, extern (Windows) int function(int, uint, int), void*, uint) is not callable using argument types (const(int), extern (Windows) int delegate(int code, uint wParam, int lParam), void*, uint) I could cast Proc to a function, obviously, but I'll loose the delegate behavior and create problems when I try to use this inside Proc?
Re: Windows Header consts
On that note, is there also any generic translation software for code that you can program a set of simple "rules"(matching and arranging) to translate source code? e.g., match("const WM_", ";")->WM.add(%1 + ",")). The above should be obvious but essentially it matches the first string until the second is found, adds it to the WM container(which, we can specify it it's type). %1 is just what was found inbetween the two bookends in the match. We add a comma for the next enum. (such a line would put all the const WM's into the enum, it doesn't handle the outer static versioning, so would break headers... hence a more robust solution is needed)
Windows Header consts
Windows headers contain a ton of global const's for the various messages. Seems like a very bad way to go about this. Could one not simply put all these in an enum? e.g., enum WM { WM_CREATE = 1, etc... }? If so, because there are so many and so many references to them, this can't be done easily by hand. Surely there is a way to automate this? But because the headers are not consistently written, a simple search and replace won't work well? e.g., const WM_* -> add to enum WM; else WM_* -> WM.* because there is code like static if (_WIN32_WINNT >= 0x500) { enum { WM_CHANGEUISTATE= 0x0127, WM_UPDATEUISTATE= 0x0128, WM_QUERYUISTATE = 0x0129 } // LOWORD(wParam) values in WM_*UISTATE* enum { UIS_SET = 1, UIS_CLEAR = 2, UIS_INITIALIZE = 3 } // HIWORD(wParam) values in WM_*UISTATE* enum { UISF_HIDEFOCUS = 0x1, UISF_HIDEACCEL = 0x2 } } static if (_WIN32_WINNT >= 0x501) { // HIWORD(wParam) values in WM_*UISTATE* enum { UISF_ACTIVE = 0x4 } } (unless one can define partial enums or use static if in the enums directly(probably the case but parsing is more difficult)) I guessing one would need a D or C parser to deal with all this?
Re: Windows Header consts
On Monday, 7 September 2015 at 20:55:25 UTC, Adam D. Ruppe wrote: On Monday, 7 September 2015 at 19:06:48 UTC, Prudence wrote: It's called encapsulation. It prevents namespace pollution and identifier collision. This is already provided by the D module system. Even if you were to define a WM_CREATE in your code, it would not cause a major problem with the Win32 name because you can disambiguate via the imports. (That's also a minor hassle, but it is more rare for these long names than a short name like WM anyway!) My editor already autocompletes WM_* names anyway, but again, the D module system can help with that too if you didn't want the keyword based completion I use for that. I just don't see any advantage here to counterbalance the pain of changing it. Again, it's called progress. Why keep using the same defunct system for endless years simply because that's the way it was done? It's like saying we should never upgrade the space shuttle(not that it matters any more) simply because the previous one was working? Do you seriously think that your logic is the best? If you could prove that Bill Gates designed the best OS ever possible, that is one thing... But changes are they shit all over themselves while doing it because they didn't learn from there mistakes(how could they, they go in to the future to see what kinda crap came out). Do you think computers in 100 years are still going to be using windows? Do you think the designers will still use the same programming techniques? Do you think they will worship Bill Gates because think they the messaging model of Windows was the ultimate gift to humanity? It's one thing to say: "I'm just too lazy to want to waste all that time changing stuff to make it work". That's a valid argument! But it's quite different to say "We don't need to change because this model works best and any modification of it will only produce a poorer result". If you are going to use the second argument, you need to prove it. If you are going to use the first, don't expect to get anywhere. I just wish when people say stuff like you have done, you would be honest and say what you really mean so we don't have to waste time beating around the bush. A simple "I'm don't care what others want, I think we should keep it the same because I'm happy with it". I'm OK with such a statement. At least it's honest and direct. I might not like the selfishness that it implies, but to each his own, I suppose. Oh, and who says you couldn't keep both systems? But I'll never understand why people think keeping a junker around and NOT allow something better is a good idea. You can keep your rusted ol' ElCamino that's missing a tire and has no hood if you want. But why stop me from having a Ferrari? Is it jealousy? Selfishness? There's enough gas to go around you know? And if we both arrive at the gas station we can take turns, if your willing?
Re: Windows Header consts
On Monday, 7 September 2015 at 22:21:28 UTC, Adam D. Ruppe wrote: On Monday, 7 September 2015 at 22:02:47 UTC, Prudence wrote: Oh, and who says you couldn't keep both systems? Nobody. There's absolutely nothing stopping you from defining your one constants and bindings. I think you should actually do it and see for yourself the pros and cons in practice. Which is why I asked is there is an easy way to do it, and you replied that essentially that it shouldn't be changed because it would change things.
Re: Windows Header consts
On Monday, 7 September 2015 at 17:59:43 UTC, Adam D. Ruppe wrote: On Monday, 7 September 2015 at 17:44:54 UTC, Prudence wrote: const WM_* -> add to enum WM; else WM_* -> WM.* I'm against that. The documentation all says WM_* and we shouldn't muck with it. huh? Are you saying you don't like to use WM.Create because it is confusing and hard for you to understand over WM_Create? Did you do a lot of win32 programming back in the day?
Re: Windows Header consts
On Monday, 7 September 2015 at 18:58:08 UTC, Adam D. Ruppe wrote: On Monday, 7 September 2015 at 18:42:59 UTC, Prudence wrote: because it is confusing and hard for you to understand over Nope, I'm saying it is a pointless change. If you do that, EVERY time you want to look something up, you need to rewrite WM.* into WM_* since that's what the docs say. And then EVERY time you copy/paste code from C or, again, the docs, you need to change it the other way. (and moreover, it won't even work, since like you pointed out, some enums have static if in part) That's a big hassle... and what's the benefit? What do you actually gain by doing this? It's called encapsulation. It prevents namespace pollution and identifier collision. It also makes intelligent easier, not to mention looks nicer, keeps everything tidy, and everything else that makes coding easier. If you think mentally changing a . to a _ is a hassle then your in trouble! An apple a day simply won't help! I understand porting code won't be as easy but a simple WM_ to WM replacement would fix 99% of the problems. Oh well, some people just don't like progress! Do you want to go back to using wooden wheels too? Is that better because it's easier to understand than the complexity of vulcanized rubber and carbon steel? Did you do a lot of win32 programming back in the day? Yup, and I still do. The documented names have worked for twenty years, why change them now? That's what I figured! Get out of the dark ages!
Re: AST like coding syntax. Easy upgrade!
On Sunday, 6 September 2015 at 20:22:23 UTC, Zoadian wrote: On Sunday, 6 September 2015 at 19:32:58 UTC, Prudence wrote: template X(Y) { string X = Y.stringof; } [...] as you'd have to write a parser for other languages why not just use strings? you can already do this: template X(string Y) { enum X = Y; } auto s = X!q{int 3;}; obviously X has to be a compiletime js->d compiler. Seriously? Is that all you got?
Re: AST like coding syntax. Easy upgrade!
On Sunday, 6 September 2015 at 20:38:44 UTC, Adam D. Ruppe wrote: On Sunday, 6 September 2015 at 20:22:23 UTC, Zoadian wrote: obviously X has to be a compiletime js->d compiler. Just a fun fact: my script.d's interpreter is itself CTFEable in modern dmd! import arsd.script; void main() { // script.d is similar to but not identical to javascript // so run that code in the interpreter and fetch a D // type right out all at compile time... enum a = interpret("var a = 5; a += 2; a;").get!int; pragma(msg, a); } $ dmd d ~/arsd/jsvar ~/arsd/script 7 jsvar.d and script.d can be found here: https://github.com/adamdruppe/arsd Yeah, but wouldn't it be so much nicer? (and probably debuggable inline) interpret({ var a = 5; a += 2; a; } With full compiler error support? (if it's not D, the external parser could return the error, line and position info) Or, maybe better yet, have the concept of "code strings". which are strings that are suppose to be interpreted as code. This then means the compiler just has to do a syntax check for errors before it does anything else with them(semantics will be checked lazy, which is already implemented).
Re: Interface "indexing"
On Sunday, 6 September 2015 at 18:11:44 UTC, Kagamin wrote: Well, you can have an array of event factories: IEvent function()[2] factories = [ factory1, factory2 ]; IEvent factory1() { return new Event1(); } IEvent factory2() { return new Event2(); } Then use enum for indexing: IEvent e = factories[NumEvent1](); Yes, I suppose an array would work, but realize that since enum is a compile time construct, the dynamic array is not necessary. And since your factories are all the time and always will be(if you change anything you have to refactor a lot of stuff). It seems all this stuff could be simplified a great deal. And no one said you wouldn't have a switch. I'm not talking about creating some tycheyon particles. I'm simply talking about some way to hide the details(which, could be done with a string mixin but at the cost of not being able to parse them and debug them well).
Re: Windows Resources
On Sunday, 6 September 2015 at 10:28:59 UTC, Kagamin wrote: On Sunday, 6 September 2015 at 02:37:21 UTC, Prudence wrote: Obviously the issue is that I'm not using any resources yet it is giving me such an error. You do. See docs for lpszMenuName field. GUI projects generated by Visual Studio include resource generation, that's why it works for them. Thanks! So how does one actually include resources such as menu's (rc files and all that) in a D project? Or am I stuff creating all that stuff programmatically?
AST like coding syntax. Easy upgrade!
template X(Y) { string X = Y.stringof; } auto s = X({int 3;}) Of course, doesn't work!! But having the ability to pass code that isn't contained in a string is very useful!! 1. A new code keyword, similar to alias. Can only be used as template parameters. If you are worried about backwards compatibility, call it _code, or __code, or __code__... I don't care, only sticks and stones hurt me. 2. The argument is only checked for syntaxical errors as the argument. It obviously will be checked. If we allow for other types of code besides D, then this won't work. We could extend code to allow for other languages(which would require their syntax checking algorithms): code(python). e.g., template PythonParser X(code(python) pythoncode) { // Parses pythoncode and coverts it into D or passes it to the python interpreter or whatever... } In this case, D will know it is python code, check for a python code parser and deal with it(use an external lib to check it or have built in grammars for such things). No code is ever actually executed by this extension in the compiler, so it's somewhat of a trivial addition. All the processing is added by the programmer. 3. stringof returns the code as a string. e.g. pythoncode.stringof is simply the string representation of the block of code passed. This complements D's mixin mechanisms by getting out of having to put code in strings, which are nearly a clusterfuck for complex code. 4. This opens the door to allow for one to migrate code easier to D. Suppose you have to transfer a large code base in, say, javascript. Instead of having to convert it all by hand, you could have something like template IncludeJS(code(javscript)) { magiccookie(javscript.stringof); } ... converts and integrates the javascript code into D or simply interprets it and returns the error code, or whatever. It's not unfeasible to think that someone could write the magiccookie that brings in all the objects, functions, and such into D to be consumed in D code. I've seen this done for several scripting languages such as lua and js.
Create a delegate function
I have code setup in such a way that I call a user defined function, e.g., void myFunc(Data d) { } myFunc has to be passed to the main code using something like void SetFunc(void function(Data) func) { ... func(myData); } What I would like to do is, instead of having to pass data to myFunc(and use the type Data in all the function types), is to sort of create a delegate: what I want to do: void myFunc() { this.d; // Ok, because somehow this = Data; } then, of course, void SetFunc(void delegate() func) { func.context = myData; func(); } void delegate() dg = { auto t = this; return; }; doesn't even work because this is not defined. My guess this is impossible without compiler support. effectively though, I don't see why we can't use this(because myFunc is being executed in a context, I simply want to set it to the right one so that the user can take advantage of it... instead of having to pass an argument instead. Any ideas how to do this? It seems we can't actually create "delegate objects" but only delegate pointers? (simply because of the restrictions the compiler places on *this*. (can't be used outside of a context, even though we can always guarantee it is in a context) How bout a new syntax for such concepts? void delegate!T(...) dg { } // identical to void dg(T this, ...) { } Hence, to call dg, we have to pass it a "this" object... hence it has a context. They can be called just like functions. dg(myData, ...);
Windows Resources
I'm trying to create a win32 window. I coped the code pretty much directly from msdn: MSG msg; BOOL bRet; WNDCLASS wc; // Register the window class for the main window. if (!hPrevInstance) { wc.style = 0; wc.lpfnWndProc = cast(WNDPROC) wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; //wc.hIcon = LoadIcon(cast(HINSTANCE) NULL, IDI_APPLICATION); //wc.hCursor = LoadCursor(cast(HINSTANCE) NULL, IDC_ARROW); wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MainMenu"; wc.lpszClassName = "MainWndClass"; if (!RegisterClass()) return FALSE; } // Create the main window. hwndMain = CreateWindow("MainWndClass", "Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, cast(HWND) NULL, cast(HMENU) NULL, hInstance, cast(LPVOID) NULL); if (!hwndMain) { auto x = GetLastError(); return FALSE; } x is 1812 = ERROR_RESOURCE_DATA_NOT_FOUND That's about as far as I can get. (what resource data? Where I do put it? How, who, when?)
Re: Windows Resources
On Sunday, 6 September 2015 at 00:29:13 UTC, Adam D. Ruppe wrote: On Saturday, 5 September 2015 at 19:06:15 UTC, Prudence wrote: That's about as far as I can get. (what resource data? Where I do put it? How, who, when?) Resource data in Windows is data compiled into your exe. It is stuff like icons, menus, or other arbitrary stuff you attach. However, the code you posted doesn't access any of that so it shouldn't be an issue here... what import did you use to access the windows api? `import core.sys.windows.windows;` or something else? Also, are you building 32 bit (the default) or 64 bit? 32-bit and I'm using the latest win32 wrappers distributed on github from someone. (suppose to be more complete than core.sys.windows) Obviously the issue is that I'm not using any resources yet it is giving me such an error. (again, I pretty much copied the code directly from MSDN)
Re: Bug in logger
On Friday, 4 September 2015 at 01:00:24 UTC, Mike Parker wrote: On Thursday, 3 September 2015 at 23:09:18 UTC, Prudence wrote: \..\..\src\phobos\std\experimental\logger\core.d(1784): Error: static variable stdLoggerThreadLogger cannot be read at compile time I'm trying to use the logger in a static this. It should work or, if it can't, quietly fail(not log anything)... and not break the program. The error tells you you're trying to use something in a compile-time context that can't be used at compile time. You *should* get errors in that situation. Can you share the offending code? Wait, that makes no sense... The error is in phobos... not my code. THAT specifically means that it is a phobos problem, irrespective of what I'm doing.
Abstractioning away main/winMain
Standard and Win32 apps are so old school! I'd like to hide WinMain by wrapping it in an application class(more or less). Essentially I have an Application class class Application { public static Application New(void delegate() entry) { } } Another module extern (Windows) int WinMain(...) { } User Module: const MyApp = Application.New({ std.stdio.writeln("MY APP IS COOL"); }); But the lamba runs into a problem because of the static nature of the program... much less figuring out how to hook WinMain up into it. Essentially I don't want the user ever to have to know how there entry point came into being but there is this funkyness about it because Application never gets any control to call the user's Entry function. Whats worse is that D tries to evaluate the lambda at compile time. It's as if D only allows non-static data inside functions. The idea is to have WinMain actually call the Entry lamba function once it gets ran(transfer control)... but this seems to be difficult or impossible with D and I'm not sure why or, if not, how to get it to work without having to make the user jump through hoops. I suppose I could create the Application(Using New instead of new) inside of WinMain, but the issue still remains on how to get the user entry point(I suppose some compile time reflection could be used?). Any ideas? (The main reason for doing this is to make it easier for writing portable apps)
Re: Abstractioning away main/winMain
On Saturday, 5 September 2015 at 01:49:22 UTC, Adam D. Ruppe wrote: On Saturday, 5 September 2015 at 01:43:43 UTC, Prudence wrote: extern (Windows) int WinMain(...) If you use WinMain in D, you'll also have to initialize the D runtime yourself, which will call static constructors and such. You'd be better off just using a regular main() function, then passing the `-L/SUBSYSTEM:WINDOWS:5.0` option to dmd when building (at least on 32 bit, not sure if it is the same on 64 bit or not) so the linker makes a gui app - same as it does when it detects a WinMain in the program. const MyApp = Application.New({ std.stdio.writeln("MY APP IS COOL"); }); Remember, gui apps don't necessarily have a console, so writeln may fail! Maybe, but the error relates to be being called statically. (The main reason for doing this is to make it easier for writing portable apps) Just using a regular main function is the most portable solution. Then just offer helper functions or something to help with the boilerplate. Essentially that is what I'm doing. I have divided the app into different types using versioning. The application class is a generic wrapper for the main possibilities(win32, Win64, mac, linux, etc). Basically WinMain is used when version is Win32 or Win64 so it is not a problem with the stuff you have mentioned. At some point I will make it all work but I need to get off the ground first. I can always force the user to jump through some hoops but I'd like to avoid that as much as possible since I'm the user and I don't like hoops.
Re: Abstractioning away main/winMain
If I use functions instead of delegates it works. I suppose the problem then is that the delegate can't create a fat pointer when used in a static context. (i.e., why the functions work) The question is, then, Can I construct a delegate manually and supply my own context pointer? e.g., class X { } void foo() { } constructDelegate(, new X()) // Creates a void delegate() with context X
A better way of managing backwards compatibility?
Dealing with changes to standardized interfacing such as api function names, namespaces, file names/module names, etc is usually impossible to do because it severs the code written before the change from the new compiler. Most people think this is the way to do it and there is no, better, alternative. Well, *NOW* there is: One could completely change D(could replace it with a Fortran version, if desired) yet still keep backwards compatibility And it would be relatively easy. "How can this be possible", you exclaim with relative disdain!! Well, there are two distinct but compatible ways: 1. Essentially keep track of the version the compiler that is currently being used to compile the project, somewhere. (or one might be able to infer this from the dates, as long as one has a date to version mapping, but this is not accurate) As long as those binaries of the compiler(and source would be nice) are somewhere, the user can be informed to download the correct version and/or have the D compiler automatically do this for it. Note though, the requirement for D is only that it can do the checking and possibly downloading of another compiler. In fact, it could have it such delegating facilities to compile Fortran by similar means or it could be the D3 compiler that downloads D1 for some ancient source code. 2. Write a translation process that essentially "updates" the source code to work. Suppose D **wanted** to change a keyword for some reason or another. The compiler first runs the code through the translation process which mostly is just a token replacer but it could be more advanced and modify function differences(such as a swapping of two parameters). The good news, is that such a feature is easy to implement as it is just a mapping of the token stream to another. The hard part is getting everyone on a high enough level to put such changes in the translation process when they modify the compiler or library or whatever. For example, if we wanted to change "for" with "pour" then the parser just as an additional step. Instead of something like: parse(token[i]); we would have: parse(translate(token[i])); Where translate is just a string to string map, and we could make translate more complex by dealing with context(parse(translate(token, i)). Again, one would have to know the version in some way. We can think of 1 and 2 as different ends of the granular spectrum. 1 will get the correct version used and use it. It has to work, if not, then it wouldn't have worked anyways(user/setup issue) since this is sort of just automating what a user can do. I believe there are already tools that sort of emulate this(allows you to switch between versions easily but they are dumb(no memory and no automation)). 2 generally deals with simple changes. The good news is that all this can come from just knowing the version to compile the source with. This then gives the compiler designer the freedom not to worry about naming stuff perfectly. Documentation is not a problem, as the same translation and versioning can be automated in the same way using the same data. e.g., go to the docs, if you are using an old version, select the version, your correct documentation shows up. What these two processes, together, do, is essentially gives a discrete "history" of the compiler. It would be like an continuous incremental backup of every change to a compiler, but since most changes do not effect source code backwards compatibility, One doesn't need every single change. It also allows one to migrate to new versions seamlessly. Imagine going from D1 to D2, but it's just D anyways because the versions "don't matter" anymore. 1. The compiler will try to translate the D1 source to the D2 source through a series of micro translations(for each version we would have a translate). If it fails at some point, it will report to the user the "errors in translation" which can be due to a syntax change that is known to break versioning. (e.g., change for(i=0;i<10;i++) to for i=0,9,1, which breaks code because of semantics... although with a more intelligent translator this specific case can easily be handled) 2. If step one fails, which depends on how many times it has to be called, the further way the versions we are going between the more likely step 1 will fail. In that case we revert the "exact" compiler needed by finding and using the correct compiler that the source code was designed with. Of course! We would want this to be build in to the compiler from day one. But step 2 saves us with D!! Since almost every version has been saved, we can pretty much use step 2 the whole time. What to this do for everyone when implemented properly? Simply keep the versions with the source code somehow(embed in source in a comment at the bottom of a file or in a configuration file somewhere), and keep the translation changes up to don't on compiler
Re: A better way of managing backwards compatibility?
On Thursday, 3 September 2015 at 21:03:05 UTC, qznc wrote: On Thursday, 3 September 2015 at 17:48:23 UTC, Prudence wrote: 2. Write a translation process that essentially "updates" the source code to work. Lucky you: https://github.com/Hackerpilot/dfix There you go!! It seems someone just as intelligent as me realizes the power of such a thing!! The only real problem is integrating it with the compiler to make it seamless. I know there are detractors who think it is too much work, but these people like to waste time, They think they have it to waste! But even spending 1 hr on trying to compile source code with versioning issues is a terrible of time that could be better used on more productive things. DFix is obviously a step in the right direction... but a few more steps are required to save the many thousands of man hours that are wasted on versioning control.
Bug in logger
\..\..\src\phobos\std\experimental\logger\core.d(1784): Error: static variable stdLoggerThreadLogger cannot be read at compile time I'm trying to use the logger in a static this. It should work or, if it can't, quietly fail(not log anything)... and not break the program.
Error reporting is terrible
After being away from D and deciding to test the idea of writing a commercial app in it, There were 2 big things that have jumped out at me: 1. The setup is a much compared to most modern day compilers and software. While VS is huge, obviously has a ton of money behind it, it installs without much fanfare. When installing VS you know that ones it's done after a few mins you can jump into programming and actually get something done. 2. The error messages in D are horrendous. They tend to be terse, point to places where the error actually doesn't occur, and almost always require one to loop up the error, if it's not obvious. This is a waste of time for the programmer. Usually the more complex code the more crypographic the errors are. 3. Since I use VS, I installed VD. It works up to a point. But is so ill-integrated into VS that it makes me want to just jump back into .NET. D is like a Ferrari owned by someone who doesn't keep it clean, forgets to change the oil and filters. Sure, it's pretty powerful but it sure looks ugly and you might not trust it in a race. VS.NET is like a sleep Lamborghini that's kept in a climate controlled show room and regularly tuned for performance.