Generation of AST for semantic rule checking
I have an idea for something. I know I can't be the only one to think this way but I can't find very much information on it. Basically, I want compile-time enforcement of semantic rules. For one example--I asked previously here--if it was possible to generate a compile-time warning or error if someone used a function without checking the return value. But that is one specific implementation of a more abstract idea: Setting up rulesets to prevent common developer errors in my codebase that trigger at compile-time. I'm wondering how to go about a more general-purpose setup. Now, if I was using C/C++, I could generate the AST (Abstract Syntax Tree) with Clang. (And if you've never done it, I strongly recommend it, it's quite beautiful.) Clang also has libclang for modifying and generating AST on-the-fly which opens up huge potential--but back to the point: if I can find how to get LDC2 to generate AST, I could write a parser and scan the AST for patterns. I've seen DIP50 and AST Macros which are very interesting... but as far as I know, it's not implemented in any compiler. So the question is: Is there a way to get LDC2 to generate AST or similar, and if not, any other way to go about this? And lastly, is there a proper term for this process, and/or a field of research? I have found GCC MELT. But documentation is sparse and it seems restricted to GCC and C/C++. I guess you could call this "static analysis" with custom rules?
Re: Is there a way to make a class variable visible but constant to outsiders, but changeable (mutable) to the class itself?
On Sunday, 22 May 2016 at 03:06:44 UTC, Mike Parker wrote: As for 'const' and '@property', neither is strictly a requirement to implement this idiom. Adding const means that Oh, and the same holds true for final, of course. It's probably what you want most of the time, but it isn't strictly necessary for the idiom.
Re: Is there a way to make a class variable visible but constant to outsiders, but changeable (mutable) to the class itself?
On Saturday, 21 May 2016 at 19:17:00 UTC, dan wrote: Thanks Vit, Meta, and Yuxuan for your speedy help! So 3 pieces to put together, function, const, and @property (and i guess final for protection against subclasses). Minimally, there are two pieces to this: a private member variable and a function. class Foo { private int _myVar; int myVar() { return _myVar; } } The private is necessary because class members in D are all public by default. If it isn't there, then _myVar can be directly modified outside of the module. Be aware, though (if you aren't already), that private members *are* accessible outside of the class in the same module, e.g.: module foo; class Foo { private int _myVar; int myVar() { return _myVar; } } void printMyVar() { import std.stdio : writeln; auto f = new Foo; writeln(f); } As for 'const' and '@property', neither is strictly a requirement to implement this idiom. Adding const means that you can call the function through const references, but if that's not something you want to allow for some reason, then don't add it. @property right now doesn't really do anything other than allow for self-documenting code. Perhaps one day it will be fully implemented and require callers to drop the parentheses in calls to @property functions, but for now it doesn't do that. Use it as much as you want, but just understand it isn't necessary for the functionality you are after.
Re: Basic question about stderr
On Saturday, 21 May 2016 at 22:11:30 UTC, chaseratx wrote: On Saturday, 21 May 2016 at 22:08:15 UTC, Era Scarecrow wrote: On Saturday, 21 May 2016 at 21:54:43 UTC, Era Scarecrow wrote: On Saturday, 21 May 2016 at 21:47:20 UTC, chaseratx wrote: Thanks Era, but I am not trying to fix the range error. That was put there intentionally to create stderr output. I wonder, this sounds like a TLS (Thread Local Storage) issue where the local thread's stderr was updated but the global (shared?) one wasn't. Well found a quick solution. gotta close the original handle first! :) stderr.close(); stderr.open("error.log", "a"); stdout.open("output.log", "a"); Oh, excellent! I will try that now. :) This should also work: stderr = File("error.log", "a"); stdout = File("output.log", "a");
Re: Is there a 128-bit integer in D?
On Saturday, 21 May 2016 at 21:51:34 UTC, Jonathan M Davis wrote: On Saturday, May 21, 2016 09:43:38 Saurabh Das via Digitalmars-d-learn wrote: I see that 'cent' and 'ucent' are reserved for future use but not yet implemented. Does anyone have a working implementation of these types? The keywords are reserved for future use not in current use. So, no, there are no 128-bit integer types in D currently. It's just that we left the door open for ourselves to add them later without breaking programs due to having to create a new keyword. Alternatively, is there an any effort towards implementation of arbitrary-sized integers in Phobos? We've had that for years. It's BigInt in std.bigint. - Jonathan M Davis Thankyou. I'll have a look at that. Saurabh
Re: Division - precision
Ah, ok, got it. thx you all.
Re: binary expression...
On 05/21/2016 12:56 PM, captain_fid wrote: > On Saturday, 21 May 2016 at 18:33:53 UTC, Anonymouse wrote: >> On Saturday, 21 May 2016 at 18:10:55 UTC, captain_fid wrote: >>> Please forgive if asked before. My google skills seemed to fail me >>> and didn't see any result from search. >>> >>> My problem is simple (though not my understanding LOL). >>> >>> struct D { >>> int value; >>> bool opEquals()(bool value) const { return (value == value); } >>> } >>> >>> D aD; >>> if (aD == 1) { // OK >>> } >>> >>> if (aD) { // Error: expression aD of type D does not have a >>> boolean value >>> } >>> >>> Is there a way to overload for this? What am I missing? >> >> struct D >> { >> int value; >> >> bool opEquals(T)(T value) const { >> return value == this.value; >> } >> >> bool opCast(T : bool)() const { >> return this != this.init; // or some such >> } >> } >> >> Not tested, written on my phone so might have missed something. > > Perfect.. and your 'phoned-in' coding is impressive. > > opCast is the biggest thing I was missing/forgetting/misunderstanding here. opCast is for explicit type conversions. However, you seem to want implicit type conversions. > I Still need to look back at what is happening with vit's solution. vit's 'alias ... this' solution is it. Here is some for info: http://ddili.org/ders/d.en/alias_this.html And here is another example if you want the 'bool' value to be calculated as opposed to being a member: struct S { int x; int y; /* Implicit type conversion to 'bool' * (Because myBoolValue() returns 'bool'.) */ alias myBoolValue this; bool myBoolValue() { return (x + y) == 7;// Some special condition } } void main() { auto a = S(1, 2); auto b = S(3, 4); assert(!a);// Calls a.myBoolValue() assert( b);// Calls b.myBoolValue() } Ali
Re: Division - precision
On 05/21/2016 02:45 PM, Rygel wrote: > Hi there. I'm a beginners, so my questions could be silly. > > double x1 = 7.0; > double x2 = 3.0; > writeln(x1 / x2); > > from this code i get: > > 2.3 > > this is ok but how can i get more digits? For example: > > 2.3. > > thx :-) There are two kinds of precision to talk about in this case: 1) The value: You can't do anything about the precision other than picking a more precise type. ('real' has more precision than 'double'.) 2) The display: You can display the value more precisely with a format specifier like "%.10f" (with 10 digit precision): import std.stdio; import std.string; void main() { double x1 = 7.0; double x2 = 3.0; pragma(msg, format("%s has %s-digit precision", double.stringof, double.dig)); writeln("Printing with too many digits:"); writefln("%.30f", x1 / x2); static const betterFormatSpec = format("%%.%sf", double.dig); writefln("Printing with just the right amount precision:"); writefln("(The format string used is \"%s\".)", betterFormatSpec); writefln(betterFormatSpec, x1 / x2); } In any case, watch Don Clugston's DConf 2016 presentation as an eye-opener and great entertainment: http://www.ustream.tv/recorded/86406491/highlight/699207 Ali
Re: Division - precision
On Saturday, 21 May 2016 at 21:45:19 UTC, Rygel wrote: Hi there. I'm a beginners, so my questions could be silly. double x1 = 7.0; double x2 = 3.0; writeln(x1 / x2); this is ok but how can i get more digits? For example: 2.3. I'm not sure how to globally set the number of output characters, but you can force it with formatting. writefln("%.10g", x1 / x2); //floating point with 10 digits of precision
Re: Basic question about stderr
On Saturday, 21 May 2016 at 22:08:15 UTC, Era Scarecrow wrote: On Saturday, 21 May 2016 at 21:54:43 UTC, Era Scarecrow wrote: On Saturday, 21 May 2016 at 21:47:20 UTC, chaseratx wrote: Thanks Era, but I am not trying to fix the range error. That was put there intentionally to create stderr output. I wonder, this sounds like a TLS (Thread Local Storage) issue where the local thread's stderr was updated but the global (shared?) one wasn't. Well found a quick solution. gotta close the original handle first! :) stderr.close(); stderr.open("error.log", "a"); stdout.open("output.log", "a"); Oh, excellent! I will try that now. :)
Re: Basic question about stderr
On Saturday, 21 May 2016 at 21:54:43 UTC, Era Scarecrow wrote: On Saturday, 21 May 2016 at 21:47:20 UTC, chaseratx wrote: Thanks Era, but I am not trying to fix the range error. That was put there intentionally to create stderr output. I'm trying to figure out how to get ALL stderr output directed to a file the same as if I had used a "2>error.log" redirect from the command line. Ahh, I didn't realize you were intentionally trying to use the exception for the error output. I wonder, this sounds like a TLS (Thread Local Storage) issue where the local thread's stderr was updated but the global (shared?) one wasn't. https://dlang.org/phobos/std_stdio.html#.stderr The stderr is defined as "File stderr", not shared. I'm convinced TLS is the likely culprit. Unless you can affect the original instantiation it probably isn't going to work. I just tried using a static this() and it has a similar effect but doesn't affect stderr. :( Ok, thanks for looking into it. It does seem like it should work (to me) since there is no apparent difference between stdout and stderr in the docs, and using open() works for stdout. Not something I could intuit. Appreciate the help.
Re: Basic question about stderr
On Saturday, 21 May 2016 at 21:54:43 UTC, Era Scarecrow wrote: On Saturday, 21 May 2016 at 21:47:20 UTC, chaseratx wrote: Thanks Era, but I am not trying to fix the range error. That was put there intentionally to create stderr output. I wonder, this sounds like a TLS (Thread Local Storage) issue where the local thread's stderr was updated but the global (shared?) one wasn't. Well found a quick solution. gotta close the original handle first! :) stderr.close(); stderr.open("error.log", "a"); stdout.open("output.log", "a");
Re: mutable keyword
On 05/21/2016 07:15 PM, Jack Applegame wrote: Really? Mutating immutable is UB too, but look at std.typecons.Rebindable. Rebindable uses a union of a mutable and an immutable variant of the type. No access to the mutable union member is provided, and it's never dereferenced by Rebindable. Assignment is done through the mutable member. So the immutable member is never overwritten explicitly, but its value does change, of course. It's supposedly not a problem that the immutable member changes, as long as nobody looks. That is, as long as nobody obtains a reference to it. Copies of the immutable member are truly immutable. For this to work, the compiler must recognize that an immutable union member isn't actually immutable when the union has mutable members as well. I don't know if this is specified anywhere, or if it's perfectly sound then. And Rebindable does give out a reference, actually. That's unacceptable, as far as I can see. Filed an issue: https://issues.dlang.org/show_bug.cgi?id=16054
Re: Basic question about stderr
On Saturday, 21 May 2016 at 21:47:20 UTC, chaseratx wrote: Thanks Era, but I am not trying to fix the range error. That was put there intentionally to create stderr output. I'm trying to figure out how to get ALL stderr output directed to a file the same as if I had used a "2>error.log" redirect from the command line. Ahh, I didn't realize you were intentionally trying to use the exception for the error output. I wonder, this sounds like a TLS (Thread Local Storage) issue where the local thread's stderr was updated but the global (shared?) one wasn't. https://dlang.org/phobos/std_stdio.html#.stderr The stderr is defined as "File stderr", not shared. I'm convinced TLS is the likely culprit. Unless you can affect the original instantiation it probably isn't going to work. I just tried using a static this() and it has a similar effect but doesn't affect stderr. :(
Re: Is there a 128-bit integer in D?
On Saturday, May 21, 2016 09:43:38 Saurabh Das via Digitalmars-d-learn wrote: > I see that 'cent' and 'ucent' are reserved for future use but not > yet implemented. Does anyone have a working implementation of > these types? The keywords are reserved for future use not in current use. So, no, there are no 128-bit integer types in D currently. It's just that we left the door open for ourselves to add them later without breaking programs due to having to create a new keyword. > Alternatively, is there an any effort towards implementation of > arbitrary-sized integers in Phobos? We've had that for years. It's BigInt in std.bigint. - Jonathan M Davis
Re: Basic question about stderr
On Saturday, 21 May 2016 at 21:40:36 UTC, Era Scarecrow wrote: On Saturday, 21 May 2016 at 21:21:31 UTC, chaseratx wrote: I'm learning D and I have a basic question. I'm trying to write stderr to a file using open() (rather than shell piping/redirection). It works for stdout but doesn't seem to work with stderr. http://pastebin.com/KgzR9wAF stdout is written to the file, but stderr is not and outputs to the shell. I'm not sure why. I Googled but couldn't find an answer. Any hints? // <= causes range violation, might use foreach instead while (i < numbers.length) { write(numbers[i], " "); stderr.write(numbers[i]*10); //force stderr, 10x to differentiate output with (stderr) { //also force stderr write(" "); } Thanks Era, but I am not trying to fix the range error. That was put there intentionally to create stderr output. I'm trying to figure out how to get ALL stderr output directed to a file the same as if I had used a "2>error.log" redirect from the command line.
Division - precision
Hi there. I'm a beginners, so my questions could be silly. double x1 = 7.0; double x2 = 3.0; writeln(x1 / x2); from this code i get: 2.3 this is ok but how can i get more digits? For example: 2.3. thx :-)
Re: mutable keyword
On Saturday, May 21, 2016 17:15:16 Jack Applegame via Digitalmars-d-learn wrote: > On Friday, 20 May 2016 at 20:46:18 UTC, Jonathan M Davis wrote: > > Casting away const and mutating is undefined behavior in D. No > > D program should ever do it. > > Really? Mutating immutable is UB too, but look at > std.typecons.Rebindable. Rebindable is in kind of a weird grey area. It involves a union, not casting, and it's only ever mutating the class reference, not the object itself. Certainly, if it mutated the object, it would be undefined behavior, but it's just mutating the reference - but then again, the type system itself doesn't really differentiate between the two. So, I suspect that what it comes down to is that Rebindable is doing something that you really shouldn't, but because it's using a union rather than a cast, and it's so limited in what it's mutating, its behavior is effectively defined in the sense that the compiler has no leeway, but's probably still technically undefined. I don't know what Walter would say though. Certainly, if casting were involved, it would be undefined behavior without question, and it's not the sort of thing that you should be doing in your own code. So, Rebindable may actually be breaking the rules, but it's so useful that we really have no other choice as long as there isn't a solution in the actual language, and it's so limited in how it goes about it, that there's really no way that it won't work even if it's not technically valid. Personally, I think that what Rebindable has to do internally to work is the biggest strike against it, but I doubt that it's enough to convince Walter that we need a proper in-language solution given how much of a horrid pain it supposedly is to sort it out in the compiler. - Jonathan M Davis
Re: Basic question about stderr
On Saturday, 21 May 2016 at 21:21:31 UTC, chaseratx wrote: I'm learning D and I have a basic question. I'm trying to write stderr to a file using open() (rather than shell piping/redirection). It works for stdout but doesn't seem to work with stderr. http://pastebin.com/KgzR9wAF stdout is written to the file, but stderr is not and outputs to the shell. I'm not sure why. I Googled but couldn't find an answer. Any hints? // <= causes range violation, might use foreach instead while (i < numbers.length) { write(numbers[i], " "); stderr.write(numbers[i]*10); //force stderr, 10x to differentiate output with (stderr) { //also force stderr write(" "); }
Basic question about stderr
I'm learning D and I have a basic question. I'm trying to write stderr to a file using open() (rather than shell piping/redirection). It works for stdout but doesn't seem to work with stderr. http://pastebin.com/KgzR9wAF stdout is written to the file, but stderr is not and outputs to the shell. I'm not sure why. I Googled but couldn't find an answer. Any hints?
Re: Small-Size-Optimized Array
On Thursday, 19 May 2016 at 06:20:24 UTC, Nikolay wrote: You can look to my experement (see iarray.d): https://bitbucket.org/sibnick/inplacearray.git Thanks!
Re: binary expression...
On Saturday, 21 May 2016 at 18:33:53 UTC, Anonymouse wrote: On Saturday, 21 May 2016 at 18:10:55 UTC, captain_fid wrote: Please forgive if asked before. My google skills seemed to fail me and didn't see any result from search. My problem is simple (though not my understanding LOL). struct D { int value; bool opEquals()(bool value) const { return (value == value); } } D aD; if (aD == 1) { // OK } if (aD) { // Error: expression aD of type D does not have a boolean value } Is there a way to overload for this? What am I missing? struct D { int value; bool opEquals(T)(T value) const { return value == this.value; } bool opCast(T : bool)() const { return this != this.init; // or some such } } Not tested, written on my phone so might have missed something. Perfect.. and your 'phoned-in' coding is impressive. opCast is the biggest thing I was missing/forgetting/misunderstanding here. I Still need to look back at what is happening with vit's solution. Sorry again for the bad example to both of you.
Re: Is there a way to make a class variable visible but constant to outsiders, but changeable (mutable) to the class itself?
Thanks Vit, Meta, and Yuxuan for your speedy help! So 3 pieces to put together, function, const, and @property (and i guess final for protection against subclasses).
Re: binary expression...
On Saturday, 21 May 2016 at 18:31:46 UTC, vit wrote: On Saturday, 21 May 2016 at 18:10:55 UTC, captain_fid wrote: Please forgive if asked before. My google skills seemed to fail me and didn't see any result from search. My problem is simple (though not my understanding LOL). struct D { int value; bool opEquals()(bool value) const { return (value == value); } } D aD; if (aD == 1) { // OK } if (aD) { // Error: expression aD of type D does not have a boolean value } Is there a way to overload for this? What am I missing? struct D { int value; alias value this;///"implicit cast" bool opEquals()(bool value) const { return (this.value == value); ///'this.' is required } } Thanks both vit and anonymouse. (And I couldn't even provide a good example -- didn't mean to use 'value' for opEquals() arg argg Regardless -- vit, your suggestion compiled (and I laughed) but I'm not sure what's getting called. The opEquals() overload doesn't seem to be it. Hard returns of true or false don't seem to impact code. Hmmm. I'll also check anoymouse's suggestion. Regardless, thanks for the assistance.
Re: Game Development Using D
On Saturday, 21 May 2016 at 15:53:18 UTC, David wrote: Hi, I want to try to create a game using D. I'm a complete newbie though (other than having C/C++ experience). Where would I start? Does D have an openGL binding? I am assuming I'll need to leverage a good amount C APIs? Any list of these that would be useful it a game setting? Obviously this all depends on *how* much work I want to do. Ideally, I'd like a collection of tools that will get me roughly the equivalent of what XNA provides. Also forgot to add this : http://defenestrate.eu/_static/ossvikend/intro-gamedev-d/slides/index.html It's an intro to D game dev
Re: problems with Rebindable
On Saturday, 21 May 2016 at 10:42:13 UTC, chmike wrote: switch(x1) { case Infos.one: writeln("case Infos.one"); break; default: writeln("default"); break; } You can generate fairly unique ids and use them in switch statements like this: https://dpaste.dzfl.pl/873b5b4cf71e
Re: Game Development Using D
On Saturday, 21 May 2016 at 15:53:18 UTC, David wrote: Hi, I want to try to create a game using D. I'm a complete newbie though (other than having C/C++ experience). Where would I start? Does D have an openGL binding? I am assuming I'll need to leverage a good amount C APIs? Any list of these that would be useful it a game setting? Obviously this all depends on *how* much work I want to do. Ideally, I'd like a collection of tools that will get me roughly the equivalent of what XNA provides. I use GFM, https://github.com/d-gamedev-team/gfm It's pretty easy to use and saves alot of headache. Downside is that the documentation is somewhat outdated (namely close() functions are deprecated, you have to use the destroy attribute, or typecons). SDL + OpenGL is easy with GFM. here is a good opengl tutorial : http://www.learnopengl.com/
Re: problems with Rebindable
On Saturday, 21 May 2016 at 13:36:02 UTC, chmike wrote: static Info one() { static auto x = Info(new Obj("I'm one")); return x; } static Info two() { static auto x = Info(new Obj("I'm two")); return x; } FYI those are thread local variables.
Re: binary expression...
On Saturday, 21 May 2016 at 18:10:55 UTC, captain_fid wrote: Please forgive if asked before. My google skills seemed to fail me and didn't see any result from search. My problem is simple (though not my understanding LOL). struct D { int value; bool opEquals()(bool value) const { return (value == value); } } D aD; if (aD == 1) { // OK } if (aD) { // Error: expression aD of type D does not have a boolean value } Is there a way to overload for this? What am I missing? struct D { int value; bool opEquals(T)(T value) const { return value == this.value; } bool opCast(T : bool)() const { return this != this.init; // or some such } } Not tested, written on my phone so might have missed something.
Re: binary expression...
On Saturday, 21 May 2016 at 18:10:55 UTC, captain_fid wrote: Please forgive if asked before. My google skills seemed to fail me and didn't see any result from search. My problem is simple (though not my understanding LOL). struct D { int value; bool opEquals()(bool value) const { return (value == value); } } D aD; if (aD == 1) { // OK } if (aD) { // Error: expression aD of type D does not have a boolean value } Is there a way to overload for this? What am I missing? struct D { int value; alias value this;///"implicit cast" bool opEquals()(bool value) const { return (this.value == value); ///'this.' is required } }
Re: Is there a way to make a class variable visible but constant to outsiders, but changeable (mutable) to the class itself?
On Saturday, 21 May 2016 at 17:32:47 UTC, dan wrote: Is it possible to have a class which has a variable which can be seen from the outside, but which can only be modified from the inside? Something like: class C { int my_var = 3; // semi_const?? void do_something() { my_var = 4; } } And then in another file auto c = new C(); c.my_var = 5; // <<<- should trigger a compile-time error writeln("the value is ", c.my_var); // <<<- should print 3 c.do_something(); writeln("the value is ", c.my_var); // <<<- should print 4 Reading Alexandrescu's book suggests the answer is "no" (the only relevant type qualifiers are private, package, protected, public, and export, and none seem appropriate). (This effect could be simulated by making my_var into a function, but i don't want to do that.) TIA for any info! dan class C { private: int my_var_ = 3; // semi_const @property final void my_var(int x){ ///private setter this.my_var_ = x; } public: @property final int my_var()const{ ///public getter return my_var_; } void do_something() { my_var = 4; } }
Re: Is there a way to make a class variable visible but constant to outsiders, but changeable (mutable) to the class itself?
On Saturday, 21 May 2016 at 17:32:47 UTC, dan wrote: Is it possible to have a class which has a variable which can be seen from the outside, but which can only be modified from the inside? Something like: class C { int my_var = 3; // semi_const?? void do_something() { my_var = 4; } } And then in another file auto c = new C(); c.my_var = 5; // <<<- should trigger a compile-time error writeln("the value is ", c.my_var); // <<<- should print 3 c.do_something(); writeln("the value is ", c.my_var); // <<<- should print 4 Reading Alexandrescu's book suggests the answer is "no" (the only relevant type qualifiers are private, package, protected, public, and export, and none seem appropriate). (This effect could be simulated by making my_var into a function, but i don't want to do that.) TIA for any info! dan You can create a const accessor for the variable. Then you can have it be mutable internally but const externally. Class C { int _my_var = 2; void setMyVarTo3() { _my_var = 3; } @property const(int) my_var() { return _my_var; } } auto c = new C(); writeln(c.my_var); //Prints 2 c.setMyVarTo3(); writeln(c.my_var); //Prints 3 c.my_var = 4; //Error, cannot modify const(int)
binary expression...
Please forgive if asked before. My google skills seemed to fail me and didn't see any result from search. My problem is simple (though not my understanding LOL). struct D { int value; bool opEquals()(bool value) const { return (value == value); } } D aD; if (aD == 1) { // OK } if (aD) { // Error: expression aD of type D does not have a boolean value } Is there a way to overload for this? What am I missing?
Re: Is there a way to make a class variable visible but constant to outsiders, but changeable (mutable) to the class itself?
On Saturday, 21 May 2016 at 17:32:47 UTC, dan wrote: Is it possible to have a class which has a variable which can be seen from the outside, but which can only be modified from the inside? Something like: class C { int my_var = 3; // semi_const?? void do_something() { my_var = 4; } } And then in another file auto c = new C(); c.my_var = 5; // <<<- should trigger a compile-time error writeln("the value is ", c.my_var); // <<<- should print 3 c.do_something(); writeln("the value is ", c.my_var); // <<<- should print 4 Reading Alexandrescu's book suggests the answer is "no" (the only relevant type qualifiers are private, package, protected, public, and export, and none seem appropriate). (This effect could be simulated by making my_var into a function, but i don't want to do that.) TIA for any info! dan class C { int my_var() { return _my_var; } int _my_var; }
Is there a way to make a class variable visible but constant to outsiders, but changeable (mutable) to the class itself?
Is it possible to have a class which has a variable which can be seen from the outside, but which can only be modified from the inside? Something like: class C { int my_var = 3; // semi_const?? void do_something() { my_var = 4; } } And then in another file auto c = new C(); c.my_var = 5; // <<<- should trigger a compile-time error writeln("the value is ", c.my_var); // <<<- should print 3 c.do_something(); writeln("the value is ", c.my_var); // <<<- should print 4 Reading Alexandrescu's book suggests the answer is "no" (the only relevant type qualifiers are private, package, protected, public, and export, and none seem appropriate). (This effect could be simulated by making my_var into a function, but i don't want to do that.) TIA for any info! dan
Re: mutable keyword
On Friday, 20 May 2016 at 20:46:18 UTC, Jonathan M Davis wrote: Casting away const and mutating is undefined behavior in D. No D program should ever do it. Really? Mutating immutable is UB too, but look at std.typecons.Rebindable.
Re: Game Development Using D
On Saturday, 21 May 2016 at 16:01:26 UTC, Stefan Koch wrote: On Saturday, 21 May 2016 at 15:53:18 UTC, David wrote: Hi, I want to try to create a game using D. I'm a complete newbie though (other than having C/C++ experience). Where would I start? Does D have an openGL binding? I am assuming I'll need to leverage a good amount C APIs? Any list of these that would be useful it a game setting? Obviously this all depends on *how* much work I want to do. Ideally, I'd like a collection of tools that will get me roughly the equivalent of what XNA provides. The is derilict-gl and then there is the dgame library Check out the DerelictOrg bindings in general: https://github.com/DerelictOrg In particular DerelictAssimp3 might help with animation and scene loading. Other related game libraries are in the dub registry: https://code.dlang.org/search?q=game
Re: Game Development Using D
On Saturday, 21 May 2016 at 15:53:18 UTC, David wrote: Hi, I want to try to create a game using D. I'm a complete newbie though (other than having C/C++ experience). Where would I start? Does D have an openGL binding? I am assuming I'll need to leverage a good amount C APIs? Any list of these that would be useful it a game setting? Obviously this all depends on *how* much work I want to do. Ideally, I'd like a collection of tools that will get me roughly the equivalent of what XNA provides. The is derilict-gl and then there is the dgame library
Game Development Using D
Hi, I want to try to create a game using D. I'm a complete newbie though (other than having C/C++ experience). Where would I start? Does D have an openGL binding? I am assuming I'll need to leverage a good amount C APIs? Any list of these that would be useful it a game setting? Obviously this all depends on *how* much work I want to do. Ideally, I'd like a collection of tools that will get me roughly the equivalent of what XNA provides.
Re: Confusion with anonymous functions and method overloads
On 05/21/2016 04:39 PM, pineapple wrote: But I don't understand why. Could someone clarify the difference between the two? Common mistake, because other languages (e.g. C#) use similar but different syntax. The `foo => bar` syntax doesn't use braces. When you add braces around bar, that's a delegate that runs bar when called. I.e., this: foo => bar is equivalent to this: (foo) {return bar;} And this: foo => {bar;} is equivalent to this: (foo) {return () {bar;};}
Re: Confusion with anonymous functions and method overloads
On Saturday, 21 May 2016 at 14:39:59 UTC, pineapple wrote: void clean(in void delegate(in T value) func){ this.clean((in T values[]) => { foreach(value; values) func(value); }); This doesn't do what you think it does. It passes a lambda that *returns* that foreach function (that returns void). void clean(in void delegate(in T value) func){ this.clean((in T values[]){ foreach(value; values) func(value); }); } This passes a lambda (that returns void). See https://dpaste.dzfl.pl/f93b9c0c8426
Confusion with anonymous functions and method overloads
I wrote a pair of methods that looked like this: void clean(in void delegate(in T value) func){ this.clean((in T values[]) => { foreach(value; values) func(value); }); } void clean(in void delegate(in T values[]) func){ ... } I was getting a compile error on the second line of that example: E:\Dropbox\Projects\d\mach\misc\refcounter.d(63): Error: none of the overloads of 'clean' are callable using argument types (void delegate() @system delegate(const(uint[]) values) pure nothrow @safe), candidates are: E:\Dropbox\Projects\d\mach\misc\refcounter.d(62): mach.misc.refcounter.RefCounter!uint.RefCounter.clean(const(void delegate(const(uint))) func) E:\Dropbox\Projects\d\mach\misc\refcounter.d(67): mach.misc.refcounter.RefCounter!uint.RefCounter.clean(const(void delegate(const(uint[]))) func) E:\Dropbox\Projects\d\mach\misc\refcounter.d(109): Error: template instance mach.misc.refcounter.RefCounter!uint error instantiating When I got rid of the "=>" and changed the first method to this, it compiled without issue: void clean(in void delegate(in T value) func){ this.clean((in T values[]){ foreach(value; values) func(value); }); } But I don't understand why. Could someone clarify the difference between the two? Thanks!
Re: problems with Rebindable
On 05/21/2016 03:36 PM, chmike wrote: Note however that it doesn't work with immutable. It only works with constant. I guess this is because immutable is "stronger" than const. I determined that only const was supported by looking at Rebindable's code. Here is the code that finally works as I want. The flyweight pattern is thus well supported with the exception that switch can't be used. using static functions to get the Infos.one also allow to implement lazy object instantiation. [...] I wasn't indeed using Rebindable correctly and it support only const objects, not immutable objects. I think your conclusion is wrong. Works fine if you add a couple `immutable`s (and change one `IInfo` to `Info`): import std.stdio; import std.typecons; interface IInfo { string toString() const; } alias Rebindable!(immutable IInfo) Info; // Compiles just fine. class Infos { static class Obj : IInfo { this(string msg) immutable { this.msg = msg; } private string msg; override string toString() const { return msg; } } static Info one() { static auto x = Info(new immutable Obj("I'm one")); return x; } static Info two() { static auto x = Info(new immutable Obj("I'm two")); return x; } } void main() { Info x1; Info x2 = Infos.one; assert(x1 is null); assert(x2 !is null); assert(x2 is Infos.one); assert(x2 == Infos.one); x1 = x2; assert(x1 is x2); assert(x1 == x2); assert(x1 is Infos.one); assert(x1 == Infos.one); writeln(x1); Info x3 = Info(new immutable Infos.Obj("I'm one")); assert(x1 !is x3); assert(x1 != x3); // Because there is no opEqual for deep equality test Info o1 = new immutable Infos.Obj("I'm one"), o2 = new immutable Infos.Obj("I'm one"); assert(o1 !is o2); assert(o1 != o2); // What I need for the flyweight pattern /* -- Doesn't compile : x1 is not a string or integral value switch(x1) { case Infos.one: writeln("case Infos.one"); break; default: writeln("default"); break; } */ } I thought marking the constructor `pure` would make it possible to implicitly convert a mutable `new` expression to immutable, but I couldn't get that to work. That would avoid all those `immutable`s. I'm probably forgetting something here.
Re: problems with Rebindable
On Saturday, 21 May 2016 at 13:17:11 UTC, ag0aep6g wrote: On 05/21/2016 12:42 PM, chmike wrote: Rebindable!Info x1, x2 = Infos.one; Rebindable!(immutable Info) x1, x2 = Infos.one; Indeed. Thanks. Reading the unit tests in the source code and the implementation of Rebindable helped. Note however that it doesn't work with immutable. It only works with constant. I guess this is because immutable is "stronger" than const. I determined that only const was supported by looking at Rebindable's code. Here is the code that finally works as I want. The flyweight pattern is thus well supported with the exception that switch can't be used. using static functions to get the Infos.one also allow to implement lazy object instantiation. import std.stdio; import std.typecons; interface IInfo { string toString() const; } // alias Rebindable!(immutable IInfo) Info; <-- Doesn't compile alias Rebindable!(const IInfo) Info; class Infos { static class Obj : IInfo { this(string msg) { this.msg = msg; } private string msg; override string toString() const { return msg; } } static Info one() { static auto x = Info(new Obj("I'm one")); return x; } static Info two() { static auto x = Info(new Obj("I'm two")); return x; } } void main() { Info x1; Info x2 = Infos.one; assert(x1 is null); assert(x2 !is null); assert(x2 is Infos.one); assert(x2 == Infos.one); x1 = x2; assert(x1 is x2); assert(x1 == x2); assert(x1 is Infos.one); assert(x1 == Infos.one); writeln(x1); Info x3 = Info(new Infos.Obj("I'm one")); assert(x1 !is x3); assert(x1 != x3); // Because there is no opEqual for deep equality test IInfo o1 = new Infos.Obj("I'm one"), o2 = new Infos.Obj("I'm one"); assert(o1 !is o2); assert(o1 != o2); // What I need for the flyweight pattern /* -- Doesn't compile : x1 is not a string or integral value switch(x1) { case Infos.one: writeln("case Infos.one"); break; default: writeln("default"); break; } */ } I wasn't indeed using Rebindable correctly and it support only const objects, not immutable objects. Thank you everybody for your help.
Re: problems with Rebindable
On 05/21/2016 02:17 PM, chmike wrote: On Saturday, 21 May 2016 at 10:42:13 UTC, chmike wrote: source/app.d(23,27): Error: cannot implicitly convert expression (one) of type immutable(Obj) to app.Info Apparently Rebindable doesn't support polymorphism. This is hopefully fixable. No, the difference in mutability is the problem. Can't implicitly convert class objects from immutable to mutable. [...] A Rebindable variable can't be used as a switch argument. This would require a change to the language rules. Class objects in general can't be used as switch arguments. However, the static immutable object Infos.one can be used as a case argument. How do you figure that? I get 'Error: case must be a string or an integral constant, not Obj("I'm one")'. The conclusion is that Rebindable doesn't cover the needs of a mutable object reference. I don't follow. Seems to me that the limitations you see here are in place for ordinary class objects as well. In the flyweight pattern we only need to compare object addresses and we also want to use the lazy pattern to instantiate the immutable instances. It may be possible to get pointers from the objects and switch over those pointers. Can't use class objects directly, because equality is defined by opEquals which is virtual. And a switch doesn't make sense if opEquals needs to be called. Also, I'm afraid you're going to have a bad time when trying to get lazy initialization + immutable.
Re: problems with Rebindable
On 05/21/2016 12:42 PM, chmike wrote: Rebindable!Info x1, x2 = Infos.one; Rebindable!(immutable Info) x1, x2 = Infos.one;
Re: problems with Rebindable
On Saturday, 21 May 2016 at 10:42:13 UTC, chmike wrote: source/app.d(23,27): Error: cannot implicitly convert expression (one) of type immutable(Obj) to app.Info Apparently Rebindable doesn't support polymorphism. This is hopefully fixable. source/app.d(43,5): Error: 'x1' must be of integral or string type, it is a app.Info source/app.d(45,10): Error: cannot implicitly convert expression (one) of type immutable(Obj) to app.Info A Rebindable variable can't be used as a switch argument. This would require a change to the language rules. However, the static immutable object Infos.one can be used as a case argument. The conclusion is that Rebindable doesn't cover the needs of a mutable object reference. In the flyweight pattern we only need to compare object addresses and we also want to use the lazy pattern to instantiate the immutable instances.
Re: Immutable objects and constructor ?
On Saturday, 21 May 2016 at 08:24:19 UTC, Ali Çehreli wrote: On 05/21/2016 01:07 AM, chmike wrote: > Unfortunately it is not possible to write this > > import std.typecons; > class Info{...} > rebindable!Info x; You have a capitalization typo. Rebindable is a type template, rebindable is a function template. import std.typecons; class Info{} void main() { auto x = rebindable(new immutable(Info)()); pragma(msg, typeof(x)); auto y = Rebindable!(immutable(Info))(new Info()); pragma(msg, typeof(y)); } Ali Thank you. I'll start a new thread with the subject "problems with Rebindable". See https://forum.dlang.org/post/bprfdptcvzzkfzxlh...@forum.dlang.org
problems with Rebindable
This thread is a followup of https://forum.dlang.org/post/vuljzyufphsywzevu...@forum.dlang.org with a refocused subject and question. I'm looking for a mutable reference to a none mutable object to implement the flyweight pattern. It is for a library and its user interface. So I'm not looking for hacks to get around the problem. Here is a toy example showing what I try to achieve and that fails to compile. The main shows what I expect users should be able to do. The aim is to allow the user to define another sets of constants of base type Info in his own class (e.g. MyInfos) and with a different implementation that the one provided in the example class Infos. import std.stdio; import std.typecons; interface Info { } class Infos { static class Obj : Info { this(string msg) immutable { this.msg = msg; } private string msg; string toString() immutable { return msg; } } static immutable one = new immutable Obj("I'm one"); } void main() { Rebindable!Info x1, x2 = Infos.one; assert(x1 is null); assert(x1 == null); assert(x2 !is null); assert(x2 != null); assert(x2 is Infos.one); assert(x2 == Infos.one); x1 = x2; assert(x1 is x2); assert(x1 == x2); assert(x1 is Infos.one); assert(x1 == Infos.one); writeln(x1); switch(x1) { case Infos.one: writeln("case Infos.one"); break; default: writeln("default"); break; } // That is enough for today } Compiling this code with dmd $ dmd --version DMD64 D Compiler v2.071.0 Copyright (c) 1999-2015 by Digital Mars written by Walter Bright I get the following errors: $ dub build Performing "debug" build using dmd for x86_64. testrebindable ~master: building configuration "application"... source/app.d(23,27): Error: cannot implicitly convert expression (one) of type immutable(Obj) to app.Info source/app.d(26,12): Error: use 'is' instead of '==' when comparing with null source/app.d(29,12): Error: use '!is' instead of '!=' when comparing with null source/app.d(43,5): Error: 'x1' must be of integral or string type, it is a app.Info source/app.d(45,10): Error: cannot implicitly convert expression (one) of type immutable(Obj) to app.Info dmd failed with exit code 1.
Is there a 128-bit integer in D?
I see that 'cent' and 'ucent' are reserved for future use but not yet implemented. Does anyone have a working implementation of these types? Alternatively, is there an any effort towards implementation of arbitrary-sized integers in Phobos? Thanks, Saurabh
Re: Is there a 128-bit integer in D?
On Saturday, 21 May 2016 at 09:43:38 UTC, Saurabh Das wrote: I see that 'cent' and 'ucent' are reserved for future use but not yet implemented. Does anyone have a working implementation of these types? Alternatively, is there an any effort towards implementation of arbitrary-sized integers in Phobos? Thanks, Saurabh There is BigInt in phobos.
Re: mutable keyword
On Saturday, May 21, 2016 07:00:43 ciechowoj via Digitalmars-d-learn wrote: > On Saturday, 21 May 2016 at 00:39:21 UTC, Jonathan M Davis wrote: > > Well, if you actually tried marking functions with pure, you'd > > see pretty fast that this won't work with pure. A function > > that's marked with pure cannot access any global, mutable > > state. It can only access what's passed to it (though in the > > case of a member function, that includes the this > > pointer/reference). So, your refCountPool will not be > > accessible from any pure functions. > > Well, I do not have much experience with @pure in D. But I > believe that as far as I'm not using refCounter-modifying methods > of sharedPtr (constructors, assignement, destructor) it should > work. Maybe I'll try it in some future. The problem is the global variable you were using. If the ref-counting is completely internal, then it can be pure, but it can't access global variables. I'd suggest that you read this article: http://klickverbot.at/blog/2012/05/purity-in-d/ > > You can think of pure as @noglobal, because it can't access > > global variables (unless they're constants). That's it's only > > restriction, but it's enough to make it so that the only way > > that you'd have a backdoor out of const in a pure, const member > > function is if you passed a mutable reference to the object as > > one of the function arguments. > > > > At this point, if you want ref-counting, you give up on const. > > They simply do not go together. The same goes for stuff like > > caching or lazy initialization. > > > > Sure, you can get around const to some extent by giving up on > > pure, but that only works because you're putting the state of > > the object outside of the object itself, which is usally a bad > > idea. It also makes it so that const seems like a lie, since > > the state of the object isn't really const, since it's not > > actually in the object. > > I didn't tried the proposed solution, but if this is only > ideological problem and not a technical one, I would be good with > such a solution. On one side the memory reachable from object > isn't modified on the other side the object feels like a const > for the end-used. I mean I miss a logical const from C++ : ). Well, any function that isn't marked with pure is completely unusable in pure code, and it's generally best practice in D to use pure as much as possible. It makes it clear that the functions in question can't access anything that you don't give them, it allows for compiler optimizations in some cases, and it also makes it easier to do stuff like construct immutable objects, since if the compiler can guarantee that the return value of a pure function is unique, it can be implicitly converted to immutable (it might also be implicitly convertible to shared - I don't recall for sure). And of course, if you're interacting with D code that requires pure, then your code is going to need to work with pure. And since const is already borderline useless for heavily templated code (which anything range-based tends to be), contorting your code to favor const over pure is ill-advised. >From what I've seen, pretty much everyone who wants to do stuff like ref-counting or lazy initialization abandons trying to use const. So, if you need "mutable," I'd strongly encourage you to do the same rather than trying to put state in global variables just to have "logical" const, but it's up to you. > > The standard library already has std.typecons.RefCounted, if > > you want to ref-count anything other than classes, but it > > really doesn't work with const and fundamentally can't. In > > order to have const ref-counting, we're going to need language > > support. D does not and likely will never have any form of > > "logical" const. If it's const, it's const. Either that fits > > with what you're doing, and you can use const, or it doesn't, > > and you can't. > > I'm currently doing that, but std.typecons.RefCounted is > uncomfortable to use. Probably for reasons mentioned above. Well, fundamentally, ref-counting and const don't mix. C++ allows it by basically making it so that C++'s const guarantees nothing. All it really does is prevent accidental mutation and function as documentation that a member function isn't supposed to modify its object's state. But nothing is really guaranteed. D's const provides actual guarantees, but the result is that it's usuable in far fewer cases, because a lot of code simply doesn't work if it's forced to actually be const. So, RefCounted will work on some level, but it really isn't going to work with const, and no library solution even _can_ play nicely with const - not without throwing pure out the window anyway, and the really isn't worth it, especially since we keep getting more stuff added to the language that's able to take advantage of pure. But Walter is working on a language solution for ref-counting, and with that, it should become possible for ref-counting to play
Re: Single-Allocation Variable-Sized Array
On Wednesday, 18 May 2016 at 23:45:07 UTC, Alex Parrill wrote: In C it's called a variable-length struct or object. I don't think D implements them, but this could probably work: Thanks!
Re: union alignment
On Wednesday, 18 May 2016 at 01:46:37 UTC, tsbockman wrote: Shouldn't a union type always have an `alignof` at least as great as the `alignof` for its largest member? Apparently not; it's actually DMD and LDC that are wrong here: http://bugzilla.gdcproject.org/show_bug.cgi?id=226
Re: union alignment
On Wednesday, 18 May 2016 at 01:46:37 UTC, tsbockman wrote: Shouldn't a union type always have an `alignof` at least as great as the `alignof` for its largest member? On x86, there's a difference between the type alignment and the field alignment. The type align of ulong and double are 8 bytes on both x86 and x86_64. The field align is worked out differently, something to the effect of: uint fieldalignof(T)() { version (X86_64) return T.alignof; else version (X86) { static if (isIntegral!T || is(T == double) || is(T == cdouble)) return min(4, T.alignof); else return T.alignof; } } static assert(ulong.alignof == 8); static assert(double.alignof == 8); static assert(fieldalignof!ulong == 4); static assert(fieldalignof!double == 4); DMD 32: sizeof: (8 >= 8) == true alignof: (4 >= 4) == true GDC 32: sizeof: (8 >= 8) == true alignof: (4 >= 8) == false <<= Bug? LDC 32: sizeof: (8 >= 8) == true alignof: (4 >= 4) == true GDC is in the right, it's all other compilers that are wrong. :-) Iain.
Re: Immutable objects and constructor ?
On 05/21/2016 01:07 AM, chmike wrote: > Unfortunately it is not possible to write this > > import std.typecons; > class Info{...} > rebindable!Info x; You have a capitalization typo. Rebindable is a type template, rebindable is a function template. import std.typecons; class Info{} void main() { auto x = rebindable(new immutable(Info)()); pragma(msg, typeof(x)); auto y = Rebindable!(immutable(Info))(new Info()); pragma(msg, typeof(y)); } Ali
Re: Immutable objects and constructor ?
Since I'm trying to implement a flyweight pattern, the opEqual need only comparision of reference in my case. By the way, what operation is the switch performing ? OpEqual or is ?
Re: Immutable objects and constructor ?
Unfortunately it is not possible to write this import std.typecons; class Info{...} rebindable!Info x; I get the following error message source/app.d(11,3): Error: template std.typecons.rebindable matches more than one template declaration: /usr/include/dmd/phobos/std/typecons.d(1675,14): rebindable(T)(T obj) if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T) and /usr/include/dmd/phobos/std/typecons.d(1694,14): rebindable(T)(Rebindable!T obj) This would have been equivalent to define a mutable reference to an object of type Info and allow me to write this alias rebindable!Info InfoR; InfoR x; Unfortunately I didn't manage to get something compiling with rebindable. I don't understand how I'm supposed to use it. Note that I'm designing a library that I would like intuitive to use. Hacking around the problem won't cut it. I need a type defining a mutable reference to an immutable object. Rebindable doesn't give me that apparently. I need something allowing me to write this interface Info {...} class MyInfos { static class Obj : Info {...} static immutable Obj one = new immutable Obj(...); } mutableObjectRef!Info x1, x2; assert(x1 is null); assert(x1 == null); x1 = MyInfos.one; assert(x1 is MyInfos.one); assert(x1 == MyInfos.one); x2 = x1; switch(x1){ case MyInfos.one: ... ; default:...; } x1 must have the semantic of an object reference, support polymorphism, allowing to down or up cast and of course access immutable members and methods. MyInfos.one is an object reference that I shouldn't be allowed to modify. I can't use a function because it needs the value semantic so I can use it as a case argument in a switch. It doesn't seam that this is what rebind provides. It looks like mutableObjectRef should be a templated struct. But I'm not experienced enough in D to implement it. I don't know if its only possible.
Re: mutable keyword
On Saturday, 21 May 2016 at 00:39:21 UTC, Jonathan M Davis wrote: Well, if you actually tried marking functions with pure, you'd see pretty fast that this won't work with pure. A function that's marked with pure cannot access any global, mutable state. It can only access what's passed to it (though in the case of a member function, that includes the this pointer/reference). So, your refCountPool will not be accessible from any pure functions. Well, I do not have much experience with @pure in D. But I believe that as far as I'm not using refCounter-modifying methods of sharedPtr (constructors, assignement, destructor) it should work. Maybe I'll try it in some future. You can think of pure as @noglobal, because it can't access global variables (unless they're constants). That's it's only restriction, but it's enough to make it so that the only way that you'd have a backdoor out of const in a pure, const member function is if you passed a mutable reference to the object as one of the function arguments. At this point, if you want ref-counting, you give up on const. They simply do not go together. The same goes for stuff like caching or lazy initialization. Sure, you can get around const to some extent by giving up on pure, but that only works because you're putting the state of the object outside of the object itself, which is usally a bad idea. It also makes it so that const seems like a lie, since the state of the object isn't really const, since it's not actually in the object. I didn't tried the proposed solution, but if this is only ideological problem and not a technical one, I would be good with such a solution. On one side the memory reachable from object isn't modified on the other side the object feels like a const for the end-used. I mean I miss a logical const from C++ : ). The standard library already has std.typecons.RefCounted, if you want to ref-count anything other than classes, but it really doesn't work with const and fundamentally can't. In order to have const ref-counting, we're going to need language support. D does not and likely will never have any form of "logical" const. If it's const, it's const. Either that fits with what you're doing, and you can use const, or it doesn't, and you can't. I'm currently doing that, but std.typecons.RefCounted is uncomfortable to use. Probably for reasons mentioned above.
Re: Enum that can be 0 or null
On Saturday, 21 May 2016 at 01:09:42 UTC, Alex Parrill wrote: On Friday, 20 May 2016 at 22:10:51 UTC, tsbockman wrote: If that's not a satisfactory answer, please show some specific examples of code that you don't know how to make work without VK_NULL_HANDLE so that I can propose a workaround. Because, as I mentioned in the OP, for VK_NULL_HANDLE to work like it does in C on 32-bit systems, it needs to be compatible with both pointer types (VkDevice, VkInstance, etc) and 64-bit integer types (VkFence, VkSemaphore, many others). That is not code. As I said, there are many possible workarounds, but it is hard to say which is best for you without actually seeing your code. As an example, if VK_NULL_HANDLE only ever needs to be assigned to opaque types on the D side (that is, types that serve only as an ID or address for communicating with the C side), you could do this: private struct VkNullHandle { } enum VK_NULL_HANDLE = VkNullHandle.init; mixin template VkHandle(bool dispatchable) { static if (dispatchable || (size_t.sizeof == 8)) void* bits = null; else ulong bits = 0; this(typeof(this) that) { this.bits = that.bits; } this(VkNullHandle that) { this.bits = typeof(this.bits).init; } ref typeof(this) opAssign(typeof(this) that) { this.bits = that.bits; return this; } ref typeof(this) opAssign(VkNullHandle that) { this.bits = typeof(this.bits).init; return this; } } struct VkDevice { mixin VkHandle!true; } struct VkInstance { mixin VkHandle!true; } struct VkFence { mixin VkHandle!false; } struct VkSemaphore { mixin VkHandle!false; } void main() { VkInstance a = VK_NULL_HANDLE; VkFence b = VK_NULL_HANDLE; } (DPaste: https://dpaste.dzfl.pl/8f4ce39a907f ) The above is typesafe, and can easily be made compatible with a typical C API, since C does no parameter-related name mangling.
Re: Enum that can be 0 or null
On Saturday, 21 May 2016 at 01:53:21 UTC, Mike Parker wrote: When binding to a C library, it's desirable to have as close to the original C API as possible so that you *can* drop C snippets and examples into D code and have them just work. Obviously, 100% compatibility is not possible, but it is possible to get pretty close most of the time. The reason that VK_NULL_HANDLE cannot (currently) be directly implemented in D it is not type safe. D's type safety is usually considered to be a positive selling point for the language; that's what I mean when I say that "you aren't *supposed* to be able to just copy-paste any random C snippet into D".