Re: Problem: Cannot create class out of nothing using witchcraft
Am 16.10.2013 03:17, schrieb DoctorCaptain: I've gotten extremely close. The DPaste link that follows demonstrates three different templates: ... So is there any reason why you still pass the variadic arguments to the generator function and not do it the way I proposed in my last dpaste snippet? Even if you need the variadic arguments inside the generator for some logic you could still reference them by using the variadic arguments to the actual template.
Re: cannot call impure function ~this
On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call.
Re: cannot call impure function ~this
On Wednesday, 16 October 2013 at 07:23:45 UTC, monarch_dodra wrote: On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call. So it _could_ be impure, but mostly it isn't, right?
Re: should chain be pure
On Tuesday, 15 October 2013 at 14:15:15 UTC, bearophile wrote: Daniel Davidson: If you are agreeing that chain should be pure and it is just following all the calls and making all of them pure, until that happens by the professionals - is there a casting solution so I can fake a pure and move on? chain is a template, and in Phobos often templates are not annotated with pure/nothrow, the compiler infers those attributes. Regarding your code, perhaps you can put your call in an impure delegate and than cast it, but D has no direct means to cast purity, because it's highly unsafe and it's against the idea of having purity in the language. So I suggest to replace the pure in your function/method tree with /*pure*/, and later fix the code if/when chains becomes pure. Bye, bearophile @bearophile: The problem is actually with voldemort. Chain is implemented as: auto chain(Arg...)(Args args) { static struct Result //Non template struct { auto front(); //Non template function in a non-template struct. } } The problem is that the whole inference things stops at this level: the attributes of front are not infered, so chain is not pure simply because it isn't a template. This could be simply solved by making Result a non voldermort ChainResult outside of the body of chain. I'd do this, but Kenji had mentioned before that he thought the attributes should be inferred. So for now, I didn't personally make the effort of doing anything to fix it myself. But if someone else where make the effort, I'd review and probably pull.
Re: cannot call impure function ~this
On Wednesday, 16 October 2013 at 07:27:25 UTC, Namespace wrote: On Wednesday, 16 October 2013 at 07:23:45 UTC, monarch_dodra wrote: On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call. So it _could_ be impure, but mostly it isn't, right? I guess that's one way to put it. I'd say it *is* impure, but all its impure bits have been optimized out. That's my explanation anyways. I'm curious: Is this a problem for you? The function calling getA *can't* be pure either, so marking getA as pure is ... I was going to say useless, but I guess pure is always an optimization opportunity for the compiler. I'd file an ER, you never know.
Re: Starting D with a project in mind.
andrew@islay:~/dub$ ./build.sh Generating version file... Running gdmd... /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di:224: error: this cannot be interpreted at compile time, because it has no available source code /usr/local/gdc/include/d/4.8.2/std/net/curl.d:195: note: called from here: dur(2L) line 224 is trying to instantiate a Duration object. Any ideas ? Giving up on dub, I tried niaively to build one of the vibe.d samples directly :- andrew@islay:~/vibe.d/examples/http_server/source$ gdmd -I~/vibe.d/source app.d /data/home/andrew/vibe.d/source/vibe/stream/ssl.d:43: error: module bio is in file 'deimos/openssl/bio.d' which cannot be read Looks like I'm missing some openssl dependencies, where do these come from as they don't appear to be part of phobos ? Thanks
Re: cannot call impure function ~this
On Wednesday, 16 October 2013 at 07:32:27 UTC, monarch_dodra wrote: On Wednesday, 16 October 2013 at 07:27:25 UTC, Namespace wrote: On Wednesday, 16 October 2013 at 07:23:45 UTC, monarch_dodra wrote: On Tuesday, 15 October 2013 at 21:37:40 UTC, Namespace wrote: I get this error: /d701/f223.d(11): Error: pure function 'f223.getA' cannot call impure function 'f223.A.~this' with this code: import std.stdio; struct A { public: ~this() { writeln(DTor); } } A getA() pure nothrow { return A(); } void main() { A a = getA(); writeln(end of main); } But without pure and nothrow I get this output: end of main DTor Why the compiler thinks that the function should/could call A::~this? It could have something to do with the fact that RVO is an optimization *opportunity* that the compiler is allowed to go for, even if it changes the program output. Hoewever, being an *opportunity*, the compiler still has to make sure the code is valid without said optimization, which in this case, isn't: getA would destroy it's temporary after blitting it on the stac, leading to an impure call. So it _could_ be impure, but mostly it isn't, right? I guess that's one way to put it. I'd say it *is* impure, but all its impure bits have been optimized out. That's my explanation anyways. I'm curious: Is this a problem for you? The function calling getA *can't* be pure either, so marking getA as pure is ... I was going to say useless, but I guess pure is always an optimization opportunity for the compiler. I'd file an ER, you never know. No, I was just curious what's behind it. So specifically why the compiler could call the destructor.
Re: Problem: Cannot create class out of nothing using witchcraft
On Wednesday, 16 October 2013 at 06:09:48 UTC, Benjamin Thaut wrote: Am 16.10.2013 03:17, schrieb DoctorCaptain: I've gotten extremely close. The DPaste link that follows demonstrates three different templates: ... So is there any reason why you still pass the variadic arguments to the generator function and not do it the way I proposed in my last dpaste snippet? Even if you need the variadic arguments inside the generator for some logic you could still reference them by using the variadic arguments to the actual template. I suppose I was trying to give the class individual data members, such that passing a tuple of (WorstChild, MiddleChild, BestChild) would result in a class definition of: class MagicClass { WorstClass t1; MiddleClass t2; BestClass t3; } However, if that is impossible (and frankly it'd be more difficult to work with than your way even if it was achieved), then I'll use your approach (actually, I'm just going to use your approach anyway. It's significantly cleaner than my horrid mess of a goal). That said, what is actually happening in your example? I reworked it a bit to demonstrate that the class has accessible members within T, that can be instantiated and accessed and whatnot. http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. What is T within the generated class definition? Is this just how tuples work? T is an array of three arbitrary pointers, initially null, that can be instantiated with new to create valid pointers to objects of each type at T's indexes? Like, T in the DPaste example is an array of pointers, such that: [WorstChild*, MiddleChild*, BestChild*]? Is it literally just magic like that? Actually, let me formally present a couple of ending thoughts/questions: First, allow me to apologize for trying to force a different, messy horrid mess of a goal on you, when your initial solution was majestic to begin with. Second, as I was trying to figure out just a moment ago, what -exactly- is T in the generated class definition, and why does it allow me to use it as an arbitrary container for objects of the arbitrary types I want it to contain (Read: why is it able to do exactly what I want it to be able to do? What's going on behind the scenes?)? Third, given that I am going to go with your solution (it works, it works well, and I can't seem to force my original goal to work, whether that was even a good idea to begin with at all (it wasn't)), can you think of a way to actually produce my original goal? That is, instead of a container T which I can use to access my arbitrary data members once the generated class is instantiated, is it actually even possible to generate individual data members, a la: class MagicClass { T[0] t0; T[1] t1; // ... etc } // ? You've been wildly helpful, and admirably concise. I am -extremely- interested in the answer to the second thought, and while I'm sure the answer is simple, it also seems -too- magic to actually work, and yet it does. Again, thank you to everyone who responded, and thank you Benjamin for your continued help.
Re: Starting D with a project in mind.
On Wednesday, 16 October 2013 at 07:52:44 UTC, Andrew wrote: andrew@islay:~/dub$ ./build.sh Generating version file... Running gdmd... /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di:224: error: this cannot be interpreted at compile time, because it has no available source code /usr/local/gdc/include/d/4.8.2/std/net/curl.d:195: note: called from here: dur(2L) line 224 is trying to instantiate a Duration object. Any ideas ? Giving up on dub, I tried niaively to build one of the vibe.d samples directly :- andrew@islay:~/vibe.d/examples/http_server/source$ gdmd -I~/vibe.d/source app.d /data/home/andrew/vibe.d/source/vibe/stream/ssl.d:43: error: module bio is in file 'deimos/openssl/bio.d' which cannot be read Looks like I'm missing some openssl dependencies, where do these come from as they don't appear to be part of phobos ? Thanks As far as I know deimos is a set of official (?) bindings for common C libraries. I don't know dub's build process but I assume that if the build script would have worked for you it would have attempted to clone this repo https://github.com/D-Programming-Deimos/openssl (you can find more bindings if you go up one level). My gdc build hadn't finished yet when I had to leave for work this morning, but I'll try to build dub tonight, to see if I run into the same problems...
Re: Starting D with a project in mind.
As far as I know deimos is a set of official (?) bindings for common C libraries. I don't know dub's build process but I assume that if the build script would have worked for you it would have attempted to clone this repo https://github.com/D-Programming-Deimos/openssl (you can find more bindings if you go up one level). My gdc build hadn't finished yet when I had to leave for work this morning, but I'll try to build dub tonight, to see if I run into the same problems... I've been using a Cubieboard A20, it's much better than a RPi as it has 1GB RAM, dual core armv7 and much better IO including on-board SATA for $50. The gcc /gdc build takes around 2 - 3 hours on that. You'll probably run into the same libphobos issues that I had, since there are many places where there are no ARM headers.
Re: Starting D with a project in mind.
On Wednesday, 16 October 2013 at 07:52:44 UTC, Andrew wrote: Giving up on dub, I tried niaively to build one of the vibe.d samples directly This is something I have used with vibe.d in absence of dub (untested, from my memory): git clone https://github.com/D-Programming-Deimos/openssl git clone https://github.com/D-Programming-Deimos/libevent git clone https://github.com/rejectedsoftware/vibe.d cd myvibeapp rdmd --compiler=gdmd2 -I../openssl/ -I../libevent -I../vibe.d/source -J./views/ -version=VibeLibeventDriver --build-only source/app.d Usage of `rdmd` is crucial here as you need something to take care of compiling all imported modules. dmd/gdc/ldc don't do it on their own and you really don't want to track that module list manually ;) rdmd sources are here (it is a small trivial D app): https://github.com/D-Programming-Language/tools
Re: Starting D with a project in mind.
On Tuesday, 15 October 2013 at 22:52:42 UTC, Andrew wrote: andrew@islay:~/dub$ ./build.sh Generating version file... Running gdmd... /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di:224: error: this cannot be interpreted at compile time, because it has no available source code /usr/local/gdc/include/d/4.8.2/std/net/curl.d:195: note: called from here: dur(2L) line 224 is trying to instantiate a Duration object. Any ideas ? Here the problem is that your install script has provided only *.di files as bindings to druntime and `dub` tries to use some of those function for compile-time constfolding (CTFE) which requires having full function source. *.di are supposed to be bindings to library blobs for cases when you want to hide implementation from end user, no idea why those are used here. Normal DMD install puts those as plain *.d modules.
Re: Starting D with a project in mind.
On Tuesday, 15 October 2013 at 23:16:07 UTC, Brad Roberts wrote: I think you mean catch-22 rather than dead-end. There's not more people helping support ARM due to ARM not yet working well, so there's no developers. ARM's not exotic, it's just not on as many people's desktops. Thats been changing rapidly over the last several years. In my opinion catch-22 is partial case of a dead-end - something that blocks your effective forward movement :) ARM support is rather exotic among projects of current D users.
Re: Syntax for heap allocated void initialized arrays
Timothee Cour: is the following true? int*[N] a=void; foreach(i;N) a[i]=fillValue(i);// some leaks may occur during foreach loop //at the next GC run, no more leaks due to that piece of code I think so, but I am not an expert on GC matters, I have not yet written a similar GC. Bye, bearophile
Re: Starting D with a project in mind.
On Tuesday, 15 October 2013 at 23:03:15 UTC, Andrew wrote: Thanks for your patience supporting me BTW. You are welcome. D development is pure open-source movement with all its pros and cons - almost anyone here will gladly help you not only because we care about a good public image but because it gives a chance that you may investigate and improve situation in currently under-explored domain, to the greater community benefit. It is very important to have someone with personal interest in such development areas, helping with few cheap advises is the very least we can do :)
Interfacing via Java Native Interface
Hello there! I've decided to learn a bit of D, as I am currently Android Developer (mostly C++ - JNI - Java), I'm trying to create a D shared library which exports function (with extern (C)) for invocation from Java. My .d file contains only a single function returning an int, .java calls this function several times. This approach only works if d-function is trivial, e.g. it's not using any D functionality (I believe that it is related to GC and memory allocation). For example, if my d-function just returns some constant integer, java side receives it. core.stdc.stdio also works and allows console output, but it's not the case with std.stdio.writeln and similar functions. If I use any d-specific functions my program crashes while calling native code with some weird message like following: Invalid memory access of location 0x0 rip=addr. It seems like D is not initialized at all, maybe there is some internal function like dinit() which I can call in order to activate everything? Thanks.
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 10:11:32 UTC, Andrew wrote: Hello there! I've decided to learn a bit of D, as I am currently Android Developer (mostly C++ - JNI - Java), I'm trying to create a D shared library which exports function (with extern (C)) for invocation from Java. My .d file contains only a single function returning an int, .java calls this function several times. This approach only works if d-function is trivial, e.g. it's not using any D functionality (I believe that it is related to GC and memory allocation). For example, if my d-function just returns some constant integer, java side receives it. core.stdc.stdio also works and allows console output, but it's not the case with std.stdio.writeln and similar functions. If I use any d-specific functions my program crashes while calling native code with some weird message like following: Invalid memory access of location 0x0 rip=addr. It seems like D is not initialized at all, maybe there is some internal function like dinit() which I can call in order to activate everything? Thanks. JNI requires (to some degree) compiler support. This could be done in gdc as backend support is there because of g++ JNI interface to gcj. But it would be some magic module or change to the language to add the Java types to the language. Regards Iain.
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 10:15:17 UTC, Iain Buclaw wrote: On Wednesday, 16 October 2013 at 10:11:32 UTC, Andrew wrote: Hello there! I've decided to learn a bit of D, as I am currently Android Developer (mostly C++ - JNI - Java), I'm trying to create a D shared library which exports function (with extern (C)) for invocation from Java. My .d file contains only a single function returning an int, .java calls this function several times. This approach only works if d-function is trivial, e.g. it's not using any D functionality (I believe that it is related to GC and memory allocation). For example, if my d-function just returns some constant integer, java side receives it. core.stdc.stdio also works and allows console output, but it's not the case with std.stdio.writeln and similar functions. If I use any d-specific functions my program crashes while calling native code with some weird message like following: Invalid memory access of location 0x0 rip=addr. It seems like D is not initialized at all, maybe there is some internal function like dinit() which I can call in order to activate everything? Thanks. JNI requires (to some degree) compiler support. This could be done in gdc as backend support is there because of g++ JNI interface to gcj. But it would be some magic module or change to the language to add the Java types to the language. Regards Iain. As far as I know, calling C from Java only requires is jni.h header. It can mimicked with mere D aliases. I'm currently not talking about calling Java from D, although it could be possible by writing C-wrapper library. I just can't understand why D code compiled as a shared library does not work when called from Java. Why does it (does it?) work when called from C?
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 10:11:32 UTC, Andrew wrote: Hello there! I've decided to learn a bit of D, as I am currently Android Developer (mostly C++ - JNI - Java), I'm trying to create a D shared library which exports function (with extern (C)) for invocation from Java. My .d file contains only a single function returning an int, .java calls this function several times. This approach only works if d-function is trivial, e.g. it's not using any D functionality (I believe that it is related to GC and memory allocation). For example, if my d-function just returns some constant integer, java side receives it. core.stdc.stdio also works and allows console output, but it's not the case with std.stdio.writeln and similar functions. If I use any d-specific functions my program crashes while calling native code with some weird message like following: Invalid memory access of location 0x0 rip=addr. It seems like D is not initialized at all, maybe there is some internal function like dinit() which I can call in order to activate everything? Thanks. Try using Runtime.init() from core.runtime
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 10:15:17 UTC, Iain Buclaw wrote: On Wednesday, 16 October 2013 at 10:11:32 UTC, Andrew wrote: Hello there! I've decided to learn a bit of D, as I am currently Android Developer (mostly C++ - JNI - Java), I'm trying to create a D shared library which exports function (with extern (C)) for invocation from Java. My .d file contains only a single function returning an int, .java calls this function several times. This approach only works if d-function is trivial, e.g. it's not using any D functionality (I believe that it is related to GC and memory allocation). For example, if my d-function just returns some constant integer, java side receives it. core.stdc.stdio also works and allows console output, but it's not the case with std.stdio.writeln and similar functions. If I use any d-specific functions my program crashes while calling native code with some weird message like following: Invalid memory access of location 0x0 rip=addr. It seems like D is not initialized at all, maybe there is some internal function like dinit() which I can call in order to activate everything? Thanks. JNI requires (to some degree) compiler support. This could be done in gdc as backend support is there because of g++ JNI interface to gcj. But it would be some magic module or change to the language to add the Java types to the language. Regards Iain. I was talking about calling D from Java in following fashion: https://gist.github.com/DieHertz/7005898 Java calls dinit in static initializer after loading shader library and then proceeds with calling dget.
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 10:53:28 UTC, Andrew wrote: On Wednesday, 16 October 2013 at 10:41:35 UTC, John Colvin wrote: On Wednesday, 16 October 2013 at 10:11:32 UTC, Andrew wrote: Hello there! I've decided to learn a bit of D, as I am currently Android Developer (mostly C++ - JNI - Java), I'm trying to create a D shared library which exports function (with extern (C)) for invocation from Java. My .d file contains only a single function returning an int, .java calls this function several times. This approach only works if d-function is trivial, e.g. it's not using any D functionality (I believe that it is related to GC and memory allocation). For example, if my d-function just returns some constant integer, java side receives it. core.stdc.stdio also works and allows console output, but it's not the case with std.stdio.writeln and similar functions. If I use any d-specific functions my program crashes while calling native code with some weird message like following: Invalid memory access of location 0x0 rip=addr. It seems like D is not initialized at all, maybe there is some internal function like dinit() which I can call in order to activate everything? Thanks. Try using Runtime.init() from core.runtime Wow, thanks! Now everything works, proving that my guess on uninitialized runtime was correct. No problem. It's actually Runtime.initialize() according to documentation, by the way. Ah yeah, sorry I misremembered.
Re: Interfacing via Java Native Interface
On 2013-10-16 12:53, Andrew wrote: Wow, thanks! Now everything works, proving that my guess on uninitialized runtime was correct. It's actually Runtime.initialize() according to documentation, by the way. If you're calling it from C it might be more correct to call this function: https://github.com/D-Programming-Language/druntime/blob/master/src/rt/dmain2.d#L161 It's what Runtime.initialize calls. -- /Jacob Carlborg
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 11:01:33 UTC, Jacob Carlborg wrote: On 2013-10-16 12:53, Andrew wrote: Wow, thanks! Now everything works, proving that my guess on uninitialized runtime was correct. It's actually Runtime.initialize() according to documentation, by the way. If you're calling it from C it might be more correct to call this function: https://github.com/D-Programming-Language/druntime/blob/master/src/rt/dmain2.d#L161 It's what Runtime.initialize calls. Agreed. You can't call Runtime.initialize from outside D due to name mangling (and maybe ABI, depending on your system). However, other than that it really makes no difference which you call, Runtime.initialize is just a no-op wrapper around rt_init.
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 11:01:33 UTC, Jacob Carlborg wrote: On 2013-10-16 12:53, Andrew wrote: Wow, thanks! Now everything works, proving that my guess on uninitialized runtime was correct. It's actually Runtime.initialize() according to documentation, by the way. If you're calling it from C it might be more correct to call this function: https://github.com/D-Programming-Language/druntime/blob/master/src/rt/dmain2.d#L161 It's what Runtime.initialize calls. Thanks for advice, I'll use it when I'm interfacing C with D :-) For now I can't use it directly because a native function called from java requires a name with Java_ prefix, so I'd have to write a wrapper with such prefix anyway.
Re: Starting D with a project in mind.
On Wednesday, 16 October 2013 at 09:11:16 UTC, Andrew wrote: As far as I know deimos is a set of official (?) bindings for common C libraries. I don't know dub's build process but I assume that if the build script would have worked for you it would have attempted to clone this repo https://github.com/D-Programming-Deimos/openssl (you can find more bindings if you go up one level). My gdc build hadn't finished yet when I had to leave for work this morning, but I'll try to build dub tonight, to see if I run into the same problems... I've been using a Cubieboard A20, it's much better than a RPi as it has 1GB RAM, dual core armv7 and much better IO including on-board SATA for $50. The gcc /gdc build takes around 2 - 3 hours on that. You'll probably run into the same libphobos issues that I had, since there are many places where there are no ARM headers. Ok, I logged onto my Pi during lunch break, and actually the compilation process went fine, and pragma(msg, __VERSION__); now correctly has 2063L as output. So in my recent experience: - GDC master branch doesn't compile properly, because it's missing the ARM-specific code. - GDC-jp91 master branch compiles, but is based on 2.060 and is too old to be useful. - GDC-jp91 arm branch seems to work, although Johannes has warned that there is some codegen bug when compiling with -O2. This is all now a bit confusing, but I expect GDC master branch to compile again for ARM when either frontend version 2.064 is released and merged into GDC (in a few weeks hopefully?), or Johannes' arm fork is merged into GDC (whenever he has time to find and fix his codegen bug). Then everything would be (relatively) easy again... Looking into dub / vibe.d is out of my lunch scope :-P
UDAs on templates
It seems that __traits(getAttributes, T) returns an empty tuple for any template (or template function) T, no matter what UDAs T has been given. Am I doing something wrong? @(1) void foo(T)(){} pragma(msg, __traits(getAttributes, foo)); // tuple() pragma(msg, __traits(getAttributes, foo!int)); // tuple(1)
Re: UDAs on templates
On Wednesday, 16 October 2013 at 12:26:34 UTC, John Colvin wrote: It seems that __traits(getAttributes, T) returns an empty tuple for any template (or template function) T, no matter what UDAs T has been given. Am I doing something wrong? @(1) void foo(T)(){} pragma(msg, __traits(getAttributes, foo)); // tuple() pragma(msg, __traits(getAttributes, foo!int)); // tuple(1) I think this gets re-written like this: template foo(T) { @(1) void foo() {} } ..which does explain the observed behavior. As a workaround you can define some default guard value of T and assert inside foo() call if it is actually ever used.
Re: UDAs on templates
(quick experiments show that one can't attached UDA to template symbol itself by any means - weird limitation, don't know the rationale behind this)
Re: UDAs on templates
On Wednesday, 16 October 2013 at 13:12:39 UTC, Max Samukha wrote: I'd rather have the same set of attributes on both the template and its instantiations Impossible, ignore
Re: UDAs on templates
On Wednesday, 16 October 2013 at 12:37:23 UTC, Dicebot wrote: (quick experiments show that one can't attached UDA to template symbol itself by any means - weird limitation, don't know the rationale behind this) It is understandable why the attribute is transferred to the instantiation of the function template, though I'd rather have the same set of attributes on both the template and its instantiations in this case. There is no reason why attributes cannot be applied to templates themselves. I think that's a bug.
Re: UDAs on templates
On Wednesday, 16 October 2013 at 13:14:31 UTC, Max Samukha wrote: On Wednesday, 16 October 2013 at 13:12:39 UTC, Max Samukha wrote: I'd rather have the same set of attributes on both the template and its instantiations Impossible, ignore @(1) template Foo(T : int) {} @(2) template Foo(T : short) {} __traits(getAttributes, Foo) == ? The current semantics seems quite reasonable.
Re: Interfacing via Java Native Interface
Would you mind posting your example code? I'm supposed to be exploring using D on android myself next week and a little kick to help get started would be cool; I've never actually done any android stuff. As I understand it though, you aren't supposed to use native code for the bulk of the app which sucks. But still some D is better than no D.
Re: UDAs on templates
On Wednesday, 16 October 2013 at 13:24:59 UTC, Max Samukha wrote: @(1) template Foo(T : int) {} @(2) template Foo(T : short) {} __traits(getAttributes, Foo) == ? The current semantics seems quite reasonable. @(1) void foo(int) {} @(2) void foo(double) {} pragma(msg, __traits(getAttributes, foo)); void main() {} // Compilation output: // // tuple(1)
Re: should chain be pure
On Wednesday, October 16, 2013 09:29:31 monarch_dodra wrote: The problem is that the whole inference things stops at this level: the attributes of front are not infered, so chain is not pure simply because it isn't a template. http://d.puremagic.com/issues/show_bug.cgi?id=10329 And I think that there are older bug reports which are similar. Regardless, attribute inference is pretty poor right now. A _lot_ of Phobos doesn't have its attributes being properly inferred precisely because the compiler stops at the first level of templated stuff rather than fully inferring a template, which quickly makes attribute inference nearly useless. It should definitely be fixed at the compiler level though. Anything else would just be patching holes in a sinking ship. - Jonathan M Davis
Re: Problem: Cannot create class out of nothing using witchcraft
Oh something I forgot. You should really start littering your code with pragma(msg, ...) statements to better understand what it does. You can for example make your generator output pramga(msg, T.stringof); to find out what T actually is. Kind Regards Benjamin Thaut
Re: Problem: Cannot create class out of nothing using witchcraft
Am 16.10.2013 10:40, schrieb DoctorCaptain: On Wednesday, 16 October 2013 at 06:09:48 UTC, Benjamin Thaut wrote: Am 16.10.2013 03:17, schrieb DoctorCaptain: I've gotten extremely close. The DPaste link that follows demonstrates three different templates: ... So is there any reason why you still pass the variadic arguments to the generator function and not do it the way I proposed in my last dpaste snippet? Even if you need the variadic arguments inside the generator for some logic you could still reference them by using the variadic arguments to the actual template. I suppose I was trying to give the class individual data members, such that passing a tuple of (WorstChild, MiddleChild, BestChild) would result in a class definition of: class MagicClass { WorstClass t1; MiddleClass t2; BestClass t3; } However, if that is impossible (and frankly it'd be more difficult to work with than your way even if it was achieved), then I'll use your approach (actually, I'm just going to use your approach anyway. It's significantly cleaner than my horrid mess of a goal). That said, what is actually happening in your example? I reworked it a bit to demonstrate that the class has accessible members within T, that can be instantiated and accessed and whatnot. http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. What is T within the generated class definition? Is this just how tuples work? T is an array of three arbitrary pointers, initially null, that can be instantiated with new to create valid pointers to objects of each type at T's indexes? Like, T in the DPaste example is an array of pointers, such that: [WorstChild*, MiddleChild*, BestChild*]? Is it literally just magic like that? Actually, let me formally present a couple of ending thoughts/questions: First, allow me to apologize for trying to force a different, messy horrid mess of a goal on you, when your initial solution was majestic to begin with. No problem, I can understand that you want to stick with your solution. But as Artur explained the template is actually not able to see the actual types directly and thats why full qualified identifier will not work. Second, as I was trying to figure out just a moment ago, what -exactly- is T in the generated class definition, and why does it allow me to use it as an arbitrary container for objects of the arbitrary types I want it to contain (Read: why is it able to do exactly what I want it to be able to do? What's going on behind the scenes?)? T is the variadic argument T that is passed to the actual template GrabBagT. It might become more clear when actually copy pasting the generated code into the template. The problem is that you try to reference the classes by name. Thats not necessary. You get the classes passed in as template arguments. So you just reference them as template arguments instead of referencing them by name. It is possible to do so by not generating access via the name but instead use the template arguments passed to GrabBagT. I hope this made it a bit more clear. I might have some more time later today to look into your new examples and modify them. Third, given that I am going to go with your solution (it works, it works well, and I can't seem to force my original goal to work, whether that was even a good idea to begin with at all (it wasn't)), can you think of a way to actually produce my original goal? That is, instead of a container T which I can use to access my arbitrary data members once the generated class is instantiated, is it actually even possible to generate individual data members, a la: class MagicClass { T[0] t0; T[1] t1; // ... etc } // ? What do you need individual data members for? In my example the T members is actually a instance of a tuple which actually comes down to the exakt same data layout like individual data members. The only difference is that you access them by index and not by name. Which is actually a plus if you ask me for generic programming. You can even get back the tuple by doing typeof(members); You've been wildly helpful, and admirably concise. I am -extremely- interested in the answer to the second thought, and while I'm sure the answer is simple, it also seems -too- magic to actually work, and yet it does. Again, thank you to everyone who responded, and thank you Benjamin for your continued help. No problem. I love the metaprogramming abilities of D and a occansional challenge is always welcome ;-) -- Kind Regards Benjamin Thaut
Re: UDAs on templates
On Wednesday, 16 October 2013 at 13:38:44 UTC, Dicebot wrote: On Wednesday, 16 October 2013 at 13:24:59 UTC, Max Samukha wrote: @(1) template Foo(T : int) {} @(2) template Foo(T : short) {} __traits(getAttributes, Foo) == ? The current semantics seems quite reasonable. @(1) void foo(int) {} @(2) void foo(double) {} pragma(msg, __traits(getAttributes, foo)); void main() {} // Compilation output: // // tuple(1) That sucks. Then, getAttributes (and other traits dealing with overload sets) should return an empty set, a union or accept a pattern to match against the members of the overload set.
Re: Problem: Cannot create class out of nothing using witchcraft
Am 16.10.2013 10:40, schrieb DoctorCaptain: http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. There is actually a easier way to instanciate the elements. Just do new T[i](); no need for typeof. -- Kind Regards Benjamin Thaut
surprised by link error
The following code runs fine. There is a whole bunch of types imported, so whittling it down to the problem is not too easy. import plus.models.assumption; import pprint.pp; import std.stdio; import std.datetime; void main() { immutable am = AssumptionModel(); writeln(pp(am)); } That code writes a formatted view of the assumption model. One small code change: writeln(pp(am)); = writeln(pp(am)); Does not cause a compile error, but rather a link error (using rdmd even with --force): How is this possible? Link Error: --- errorlevel 1 | Undefined symbols for architecture x86_64: | _D44TypeInfo_HAyayS4plus6models6common9RateCurve6__initZ, referenced from: | _D6object58__T16AssociativeArrayTAyaTyS4plus6models6common9RateCurveZ16AssociativeArray6rehashMFNdZHAyayS4plus6models6common9RateCurve in linkerror.o | _D56TypeInfo_HAyayS4plus6models10assumption15DateAssumptions6__initZ, referenced from: | _D6object70__T16AssociativeArrayTAyaTyS4plus6models10assumption15DateAssumptionsZ16AssociativeArray6rehashMFNdZHAyayS4plus6models10assumption15DateAssumptions in linkerror.o | _D57TypeInfo_HAyayS4plus6models10assumption16AssetAssumptions6__initZ, referenced from: | _D6object71__T16AssociativeArrayTAyaTyS4plus6models10assumption16AssetAssumptionsZ16AssociativeArray6rehashMFNdZHAyayS4plus6models10assumption16AssetAssumptions in linkerror.o | _D61TypeInfo_HAyayS4plus6models10assumption20LiabilityAssumptions6__initZ, referenced from: | _D6object75__T16AssociativeArrayTAyaTyS4plus6models10assumption20LiabilityAssumptionsZ16AssociativeArray6rehashMFNdZHAyayS4plus6models10assumption20LiabilityAssumptions in linkerror.o | ld: symbol(s) not found for architecture x86_64 | collect2: ld returned 1 exit status -- Original successful output: { (AssumptionModel).inflation = { (RateCurve).curveData = [ ] } (AssumptionModel).assetAssumptions = { } (AssumptionModel).liabilityAssumptions = { } (AssumptionModel).accountGrowthMap = { } (AssumptionModel).incomeModelOverrides = { } (AssumptionModel).expenseModelOverrides = { } (AssumptionModel).dateAssumptions = { } }
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 13:31:50 UTC, Adam D. Ruppe wrote: Would you mind posting your example code? I'm supposed to be exploring using D on android myself next week and a little kick to help get started would be cool; I've never actually done any android stuff. As I understand it though, you aren't supposed to use native code for the bulk of the app which sucks. But still some D is better than no D. I don't mind, but the code is currently Java + D without any Android. I can post it in such state, the only thing that keeps me from moving it to Android is absence of D compiler with ARM back-end (though I'm sure it exists and I have even seen some articles about building D for ARM and Android). Concluding, I can post the could if you like, or I can first try compiling it for ARM :-) You're not supposed to use native code in Android, right, but many companies do. The company I work for uses C++ in order to make project cross-platform between iOS and Android.
Re: Interfacing via Java Native Interface
On Wednesday, 16 October 2013 at 10:11:32 UTC, Andrew wrote: Hello there! I've decided to learn a bit of D, as I am currently Android Developer (mostly C++ - JNI - Java), I'm trying to create a D shared library which exports function (with extern (C)) for invocation from Java. My .d file contains only a single function returning an int, .java calls this function several times. This approach only works if d-function is trivial, e.g. it's not using any D functionality (I believe that it is related to GC and memory allocation). For example, if my d-function just returns some constant integer, java side receives it. core.stdc.stdio also works and allows console output, but it's not the case with std.stdio.writeln and similar functions. If I use any d-specific functions my program crashes while calling native code with some weird message like following: Invalid memory access of location 0x0 rip=addr. It seems like D is not initialized at all, maybe there is some internal function like dinit() which I can call in order to activate everything? Thanks. I just came here to ask same question :D
Re: this() immutable
On Thursday, 13 June 2013 at 12:29:57 UTC, Simen Kjaeraas wrote: On Thu, 13 Jun 2013 14:17:22 +0200, Stephan Schiffels stephan_schiff...@mac.com wrote: For example, is there a way of instantiating an object normally (i.e. mutable), and then later freeze it to immutable via a simple cast or so? In std.exception there is assumeUnique. It's basically just a cast, but might be good enough for you. Is there any other recourse here? Why does making `this(...) immutable` fix things below? Shouldn't that immutable designation mean no members of this will be modified? But that is the whole point of an initializer? Why does immutable make sense in this context at all? My problem is a bit more elaborate and unfortunately to initialize members I need to call standard functions that have not been made pure (but should be). struct T { int[] i; } struct S { int[] i; immutable T t; this(immutable T _t) { t = _t; } } void main() { auto t = immutable T(); auto s = immutable S(t); }
does cast make an lvalue appear to be an rvalue
The code below fails to compile due to the last line. I was hoping casting away immutable would allow the call to foo. I think it is not accepted because of the rval to ref issue. If that is the case, how can foo be called by casting? I'm not a fan of casting but I'm finding cases where it is the only recourse to create immutable data using impure functions that should be pure. Thanks Dan import std.conv; struct T { int[] i; string[string] ss; } void foo(ref T t) { } void main() { T t1; auto t2 = immutable T(); foo(t1); foo(cast()t2); }
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 17:05:25 UTC, Daniel Davidson wrote: import std.conv; struct T { int[] i; string[string] ss; } void foo(ref T t) { } void main() { T t1; auto t2 = immutable T(); foo(t1); foo(cast()t2); } It works as it should. Make a mutable copy of t2 and pass it. Or make foo() accept const. I can't imagine a single legitimate use case for destroying type system in a way you want.
Re: mutable, const, immutable guidelines
On Wednesday, 2 October 2013 at 13:09:34 UTC, Daniel Davidson wrote: I'm reviewing Ali's insightful presentation from 2013 DConf. I wonder has he or anyone else followed up on the concepts or formalized some guidelines that could achieve consensus. I definitely agree it would be helpful to have a 50 Ways To Improve Your D. The first thing I'd like to see is a set of guidelines on mutability along the lines he discussed in his talk. But as it stands, I don't know if there was any finalization/consensus. For instance, from the first two guidelines at the end (after several iterative reconstructions of those guidelines): 1. If a variable is never mutated, make it const, not immutable. 2. Make the parameter reference to immutable if that is how you will use it anyway. It is fine to ask a favor from the caller. ... If you follow (1) exclusively, why the need for immutable in the language at all? Maybe it is a philosophical question, but where does immutability really come from? Is it an aspect of some piece of data or is it a promise that function will not change it? Or is it a requirement by a function that data passed not be changed by anyone else? The two keywords cover all in some sense. I found the end of the video amusing, when one gentleman looking at a rather sophisticated canonical struct with three overloads for 'this(...)' and two overloads for opAssign, asked if all those methods were required. I think there was back and forth and head-scratching. Another asked if the language designers were happy with the resultant complexity. Naturally the answer was yes - it is a good mix. If that is the case I wonder if the reason is they don't write software in D like Ali was looking to develop. I imagine standard library code is much more functional than OO by its very nature. My money says you will not find a struct S constructed like Ali's in the wild - it is just too much boilerplate. But surely they have their own guidelines/approaches. By posting this I am not looking for a single answer to the simple question above as it is just one of many questions in the set of how do you choose among the options in general. If you have such guidelines - please post them. Thanks Dan After trying for several days to use immutable with types containing some mutable aliasing I have come to the conclusion that maybe rule number one should be: If you have a type that has now or may ever have in the future any mutable aliasing (e.g. inclusion of T[] or T1[T1] where Ts are mutable) do not ever use the immutable keyword in any context as things just break down. If you have had more success with a immutable with types containing mutable aliasing and can share your success story that would be great. As D is growing are there any out there yet offering support services? Thanks, Dan
Re: mutable, const, immutable guidelines
On 10/16/2013 10:23 AM, Daniel Davidson wrote: On Wednesday, 2 October 2013 at 13:09:34 UTC, Daniel Davidson wrote: guidelines): 1. If a variable is never mutated, make it const, not immutable. 2. Make the parameter reference to immutable if that is how you will use it anyway. It is fine to ask a favor from the caller. After trying for several days to use immutable with types containing some mutable aliasing I have come to the conclusion that maybe rule number one should be: If you have a type that has now or may ever have in the future any mutable aliasing (e.g. inclusion of T[] or T1[T1] where Ts are mutable) do not ever use the immutable keyword in any context as things just break down. I think this topic should be carried to the main newsgroup already. I am convinced that this is a language issue. :-/ Thanks, Dan Ali
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 17:16:39 UTC, Dicebot wrote: It works as it should. Make a mutable copy of t2 and pass it. Or make foo() accept const. I can't imagine a single legitimate use case for destroying type system in a way you want. How do you propose to make a mutable copy *generically*? I think a legitimate use would be the following. In the construction of S I want to use a T to construct an R. `this(...) immutable {}` prevents initialization of R in this case. Maybe immutable adorning `this()` should mean it is immutable upon the end of the construction, giving the initialization a chance to actually initialize. In the example below a better approach would be to have: R createRFromT(ref const(T) t) pure {...} but with what I'm using from phobos that is not possible. import std.conv; import std.stdio; struct R { int[] i; string[string] ss; } struct T { int[] i; string[string] ss; } struct S { R r; this(ref const(T) t) immutable { createRFromT(t, r); } } void createRFromT(ref const(T) t, ref R r) { //... } void main() { T t1; auto t2 = immutable T(); auto s = immutable S(t2); }
Re: mutable, const, immutable guidelines
On Wed, Oct 16, 2013 at 07:23:24PM +0200, Daniel Davidson wrote: On Wednesday, 2 October 2013 at 13:09:34 UTC, Daniel Davidson wrote: [...] Maybe it is a philosophical question, but where does immutability really come from? Is it an aspect of some piece of data or is it a promise that function will not change it? Or is it a requirement by a function that data passed not be changed by anyone else? I think it helps to realize that D's const system is different from C++'s. Immutable means the data will never change, ever. It means you can put that data in read-only memory, maybe burned into a ROM chip or something like that. Const means *you* can't change the data, but somebody else may be able to. Therefore: [...] After trying for several days to use immutable with types containing some mutable aliasing I have come to the conclusion that maybe rule number one should be: If you have mutable aliasing, that means the data cannot be immutable. Use const. If you have a type that has now or may ever have in the future any mutable aliasing (e.g. inclusion of T[] or T1[T1] where Ts are mutable) do not ever use the immutable keyword in any context as things just break down. Yes, because immutable means nothing, no one, can change the data after it's constructed, ever. If you want mutable aliasing, what you want is const, not immutable. If you have had more success with a immutable with types containing mutable aliasing and can share your success story that would be great. [...] Maybe it's helpful to understand how D's const system works. The following diagram may help (please excuse the ASCII graphics): const / \ mutable immutable What this means is that const subsumes mutable and immutable. A mutable type can be implicitly converted to a const type (the receiver of the const can't modify the data, which is fine since the code holding the mutable reference can still mutate it), and so can immutable (immutable cannot be modified, ever, and const doesn't let you modify it either, so it's OK to make a const reference to immutable data). However, you cannot implicitly convert between mutable and immutable, unless you're copying the data by value. So if you have immutable data and want to make changes, you have to first make a copy of the data, then mutate it at will. What's the use of immutable, you ask? Immutable makes hard guarantees about the non-changeability of some piece of data. This makes it useful for implementing strings -- in fact, the 'string' type in D is just an alias for immutable(char)[]. You can take substrings (slices) of any given string freely, and be assured that your copy of the (sub)string will never unexpectedly change its value from somewhere else in the code. This saves the need for a lot of copying, which can be costly. One interesting subtlety here is that 'string' is immutable(char)[], but not immutable(char[]). The latter would mean that the string itself can never be changed -- you couldn't assign to it, you couldn't append to it, etc., which would make strings a lot less useful than they are. But by making strings a *mutable* array of *immutable* chars, you allow the string to be appended to, substring'd, etc., all while guaranteeing that the underlying bytes themselves will never change. So you can have the best of both worlds: you can append to strings, take substrings, assign strings to each other, etc., yet at the same time be assured that the list of intermediate substrings you stored somewhere during the process will continue to retain the values you assigned to them, because the underlying bytes they point to are immutable, and therefore guaranteed never to change. T -- Just because you survived after you did it, doesn't mean it wasn't stupid!
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 17:50:48 UTC, Daniel Davidson wrote: On Wednesday, 16 October 2013 at 17:16:39 UTC, Dicebot wrote: It works as it should. Make a mutable copy of t2 and pass it. Or make foo() accept const. I can't imagine a single legitimate use case for destroying type system in a way you want. How do you propose to make a mutable copy *generically*? Recursively going through the levels of indirection via static introspection and allocating memory for new mutable counter-parts as it goes. Maybe it should belong to Phobos, no idea right now, will know once I ever find the need for it.
Re: does cast make an lvalue appear to be an rvalue
struct S { R r; this(ref immutable(T) t) immutable { r.tupleof = t.tupleof; } } ?
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 17:05:25 UTC, Daniel Davidson wrote: The code below fails to compile due to the last line. I was hoping casting away immutable would allow the call to foo. I think it is not accepted because of the rval to ref issue. If that is the case, how can foo be called by casting? I'm not a fan of casting but I'm finding cases where it is the only recourse to create immutable data using impure functions that should be pure. Thanks Dan import std.conv; struct T { int[] i; string[string] ss; } void foo(ref T t) { } void main() { T t1; auto t2 = immutable T(); foo(t1); foo(cast()t2); } foo([cast()t2][0]); (It would be good to have compound literals like in C)
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 17:58:41 UTC, Dicebot wrote: On Wednesday, 16 October 2013 at 17:50:48 UTC, Daniel Davidson wrote: On Wednesday, 16 October 2013 at 17:16:39 UTC, Dicebot wrote: It works as it should. Make a mutable copy of t2 and pass it. Or make foo() accept const. I can't imagine a single legitimate use case for destroying type system in a way you want. How do you propose to make a mutable copy *generically*? Recursively going through the levels of indirection via static introspection and allocating memory for new mutable counter-parts as it goes. Maybe it should belong to Phobos, no idea right now, will know once I ever find the need for it. I agree with the sentiment. But as it stands I think a copy should not be necessary. I could make a local mutable R, pass it to createRFromT to get it initialized and then copy it back somehow to the member variable r. That to me is silly. The copy should not be required.
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 17:55:56 UTC, Dicebot wrote: struct S { R r; this(ref immutable(T) t) immutable { r.tupleof = t.tupleof; } } ? Thanks. It is cute - but not so helpful. The example stands. I *need* to call a createRFromT. Their shapes are the same in this simple example because I simplified. Make R look like: struct R { string[string] ss; int[] j; } and the cute trick falls apart. In words, I have an R and I want to make a T. The R is const the T will be immutable because the ctor requires it. But it is technically not immutable until it is initialized.
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 18:09:55 UTC, Maxim Fomin wrote: On Wednesday, 16 October 2013 at 17:05:25 UTC, Daniel Davidson wrote: The code below fails to compile due to the last line. I was hoping casting away immutable would allow the call to foo. I think it is not accepted because of the rval to ref issue. If that is the case, how can foo be called by casting? I'm not a fan of casting but I'm finding cases where it is the only recourse to create immutable data using impure functions that should be pure. Thanks Dan import std.conv; struct T { int[] i; string[string] ss; } void foo(ref T t) { } void main() { T t1; auto t2 = immutable T(); foo(t1); foo(cast()t2); } foo([cast()t2][0]); (It would be good to have compound literals like in C) Haaah - brilliant. Scary, but brilliant.
Re: Problem: Cannot create class out of nothing using witchcraft
Am 16.10.2013 16:08, schrieb Benjamin Thaut: Am 16.10.2013 10:40, schrieb DoctorCaptain: http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. There is actually a easier way to instanciate the elements. Just do new T[i](); no need for typeof. I'm actually wrong. new T[i]() will not work because the compiler will think it is a array allocation. You actually have to use new typeof(member[i])(); I created a example which generates individual class members for each of the arguments bassed to GrabBagT: http://dpaste.dzfl.pl/eef2edec -- Kind Regards Benjamin Thaut
Re: mutable, const, immutable guidelines
On Wednesday, 16 October 2013 at 17:55:14 UTC, H. S. Teoh wrote: On Wed, Oct 16, 2013 at 07:23:24PM +0200, Daniel Davidson wrote: On Wednesday, 2 October 2013 at 13:09:34 UTC, Daniel Davidson wrote: [...] Maybe it is a philosophical question, but where does immutability really come from? Is it an aspect of some piece of data or is it a promise that function will not change it? Or is it a requirement by a function that data passed not be changed by anyone else? I think it helps to realize that D's const system is different from C++'s. Immutable means the data will never change, ever. It means you can put that data in read-only memory, maybe burned into a ROM chip or something like that. Const means *you* can't change the data, but somebody else may be able to. Therefore: [...] After trying for several days to use immutable with types containing some mutable aliasing I have come to the conclusion that maybe rule number one should be: If you have mutable aliasing, that means the data cannot be immutable. Use const. If you have a type that has now or may ever have in the future any mutable aliasing (e.g. inclusion of T[] or T1[T1] where Ts are mutable) do not ever use the immutable keyword in any context as things just break down. Yes, because immutable means nothing, no one, can change the data after it's constructed, ever. If you want mutable aliasing, what you want is const, not immutable. I think the term mutable aliasing and what you want don't work together. mutable aliasing is not about context of usage or what you want, it is a compile time attribute of a struct. I want to use associative arrays in composition because I think they are the way I view and use my data. `struct T { string[string] i; }` has mutable aliasing, like it or not. So, it is not so much that I want mutable aliasing - in fact I fear it. But once you use AAs it is a fact of life. If you have had more success with a immutable with types containing mutable aliasing and can share your success story that would be great. [...] Maybe it's helpful to understand how D's const system works. The following diagram may help (please excuse the ASCII graphics): const / \ mutable immutable What this means is that const subsumes mutable and immutable. A mutable type can be implicitly converted to a const type (the receiver of the const can't modify the data, which is fine since the code holding the mutable reference can still mutate it), and so can immutable (immutable cannot be modified, ever, and const doesn't let you modify it either, so it's OK to make a const reference to immutable data). However, you cannot implicitly convert between mutable and immutable, unless you're copying the data by value. yes - it requires transitive deep copy. So if you have immutable data and want to make changes, you have to first make a copy of the data, then mutate it at will. What's the use of immutable, you ask? Immutable makes hard guarantees about the non-changeability of some piece of data. This makes it useful for implementing strings -- in fact, the 'string' type in D is just an alias for immutable(char)[]. You can take substrings (slices) of any given string freely, and be assured that your copy of the (sub)string will never unexpectedly change its value from somewhere else in the code. This saves the need for a lot of copying, which can be costly. I agree that string behaves as you say. I don't quite agree that immutable alone is the reason it does. I think it is an byproduct of the way immutable(T)[] is implemented. It is an implementation detail and relying on that could lead to bad deduction. We covered that here in this thread: http://forum.dlang.org/post/jfjudswamyxlttgsd...@forum.dlang.org One interesting subtlety here is that 'string' is immutable(char)[], but not immutable(char[]). The latter would mean that the string itself can never be changed -- you couldn't assign to it, you couldn't append to it, etc., which would make strings a lot less useful than they are. But by making strings a *mutable* array of *immutable* chars, you allow the string to be appended to, substring'd, etc., all while guaranteeing that the underlying bytes themselves will never change. So you can have the best of both worlds: you can append to strings, take substrings, assign strings to each other, etc., yet at the same time be assured that the list of intermediate substrings you stored somewhere during the process will continue to retain the values you assigned to them, because the underlying bytes they point to are immutable, and therefore guaranteed never to change. T Agreed with the description of the behavior. But disagree on why. It works that way because T[] is modeled as contiguous memory and the api associated with slice of type immutable(T)[] means there is no unsafe sharing. So, `struct T { string[string]
Re: mutable, const, immutable guidelines
On Wednesday, 16 October 2013 at 17:55:14 UTC, H. S. Teoh wrote: Maybe it's helpful to understand how D's const system works. The following diagram may help (please excuse the ASCII graphics): const / \ mutable immutable I think people in this thread know how const works, but some think it is broken. Scenario is this: Library code: struct Foo { int x; } User code: Foo f; immutable f2 = f; This works, even though the library writer might not have anticipated that someone makes Foo immutable. However, now the library writer obliviously releases a new version of the library, which extends it like this: struct Foo { int x; private int[] history; } Unfortunately, now the user code is broken due to the freshly introduced mutable aliasing. Personally, I think is fine. Upon compilation the user code gives a error message and user developer can adapt to the code to the new library version. Some think the library writer should have a possibility to make this work.
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 18:14:22 UTC, Daniel Davidson wrote: I agree with the sentiment. But as it stands I think a copy should not be necessary. I could make a local mutable R, pass it to createRFromT to get it initialized and then copy it back somehow to the member variable r. That to me is silly. The copy should not be required. Then don't use immutable. Root of all problems with immutable comes from trying to use it for something it should never be. `immutable` means never ever can be accessed with a mutable with any compiler optimization that may come from that. Any cast is undefined behavior in a form of time bomb. Basically, only thing immutable is good at is to create some potentially shared data and slicing / reading it when needed. If you need the same data but for passing as mutable function argument, you MUST make a copy, there is no safe way around it.
Re: mutable, const, immutable guidelines
On Wed, Oct 16, 2013 at 08:49:51PM +0200, Daniel Davidson wrote: On Wednesday, 16 October 2013 at 17:55:14 UTC, H. S. Teoh wrote: On Wed, Oct 16, 2013 at 07:23:24PM +0200, Daniel Davidson wrote: [...] If you have a type that has now or may ever have in the future any mutable aliasing (e.g. inclusion of T[] or T1[T1] where Ts are mutable) do not ever use the immutable keyword in any context as things just break down. Yes, because immutable means nothing, no one, can change the data after it's constructed, ever. If you want mutable aliasing, what you want is const, not immutable. I think the term mutable aliasing and what you want don't work together. mutable aliasing is not about context of usage or what you want, it is a compile time attribute of a struct. I want to use associative arrays in composition because I think they are the way I view and use my data. `struct T { string[string] i; }` has mutable aliasing, like it or not. So, it is not so much that I want mutable aliasing - in fact I fear it. But once you use AAs it is a fact of life. [...] Is the suggestion here: use immutable in any composition context where you have slices and you want to not worry about mutable aliasing. So, do like string does: any case where you have T[] as a member, prefer immutable(T)[] since then you don't have to worry about sharing. Well, not sure that works in general because the T in string is char and has no mutable aliasing itself. Suppose T itself has mutable aliasing, then what? Or, suppose it is a struct with no mutable aliasing *now*. Who's to say it won't change. So, where does all this leave us w.r.t. a good set of guidelines? Sorry, I kinda barged into this conversation, so I'm not sure what exactly you're trying to achieve here. What kind of composition contexts do you have in mind? Maybe you could help me understand what you're trying to do? Keeping in mind that AA's, as they are currently implemented, leaves a lot of room for improvement, to say the least. So you might be running into some AA-related issues, not the type system proper. T -- Creativity is not an excuse for sloppiness.
Re: Problem: Cannot create class out of nothing using witchcraft
AWW you posted that while I was writing my latest novel. So T[i] doesn't work? I guess I shouldn't have opened my eyes this morning. In any case, typeof() DOES work, so as long as there is a way to extract the type, we're good. I am extremely pleased it's actually possible to get individual data members like I was originally attempting to do. I'm likely not going to actually do this, as your T members; solution is cleaner, but I'm glad it's not just arbitrarily impossible. Thank you so much! And I could have SWORN I tried to write something like what you have in your latest DPaste, but I must have been doing something wrong, of course. In any case, I'm glad this whole thing has been so very cleanly resolved. Infinity thank you.
Re: Problem: Cannot create class out of nothing using witchcraft
On Wednesday, 16 October 2013 at 18:47:25 UTC, Benjamin Thaut wrote: Am 16.10.2013 16:08, schrieb Benjamin Thaut: Am 16.10.2013 10:40, schrieb DoctorCaptain: http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. There is actually a easier way to instanciate the elements. Just do new T[i](); no need for typeof. I'm actually wrong. new T[i]() will not work because the compiler will think it is a array allocation. You actually have to use new typeof(member[i])(); I created a example which generates individual class members for each of the arguments bassed to GrabBagT: http://dpaste.dzfl.pl/eef2edec AWW you posted that while I was writing my latest novel. So T[i] doesn't work? I guess I shouldn't have opened my eyes this morning. In any case, typeof() DOES work, so as long as there is a way to extract the type, we're good. I am extremely pleased it's actually possible to get individual data members like I was originally attempting to do. I'm likely not going to actually do this, as your T members; solution is cleaner, but I'm glad it's not just arbitrarily impossible. Thank you so much!
Re: mutable, const, immutable guidelines
On Wednesday, 16 October 2013 at 18:52:23 UTC, qznc wrote: On Wednesday, 16 October 2013 at 17:55:14 UTC, H. S. Teoh wrote: Maybe it's helpful to understand how D's const system works. The following diagram may help (please excuse the ASCII graphics): const / \ mutable immutable I think people in this thread know how const works, but some think it is broken. Scenario is this: Thanks. Library code: struct Foo { int x; } User code: Foo f; immutable f2 = f; This works, even though the library writer might not have anticipated that someone makes Foo immutable. However, now the library writer obliviously releases a new version of the library, which extends it like this: struct Foo { int x; private int[] history; } Unfortunately, now the user code is broken due to the freshly introduced mutable aliasing. Personally, I think is fine. Upon compilation the user code gives a error message and user developer can adapt to the code to the new library version. Some think the library writer should have a possibility to make this work. I don't understand how it could be fine. As code grows it would lead to people not adding useful members like history just because of the huge repercussions. struct User { immutable(Foo) foos; } How can I as a user adapt to that change? Before the change assignment worked equally well among all of Mutable, Immutable, Const. After that change any `foos ~= createFoo(...)` would require change. And it is not clear what the change would be.
Re: mutable, const, immutable guidelines
On Wed, Oct 16, 2013 at 08:52:22PM +0200, qznc wrote: On Wednesday, 16 October 2013 at 17:55:14 UTC, H. S. Teoh wrote: Maybe it's helpful to understand how D's const system works. The following diagram may help (please excuse the ASCII graphics): const / \ mutable immutable I think people in this thread know how const works, but some think it is broken. Scenario is this: Library code: struct Foo { int x; } User code: Foo f; immutable f2 = f; This works, even though the library writer might not have anticipated that someone makes Foo immutable. However, now the library writer obliviously releases a new version of the library, which extends it like this: struct Foo { int x; private int[] history; } Unfortunately, now the user code is broken due to the freshly introduced mutable aliasing. Personally, I think is fine. Upon compilation the user code gives a error message and user developer can adapt to the code to the new library version. Some think the library writer should have a possibility to make this work. Well, I think here the type system is working as advertised. Since the original version of Foo has no mutable aliasing, implicit conversion to immutable is OK (you're making a new binary copy of the data). But in the second case, it will obviously violate immutability guarantees, because in D, immutable is transitive, so immutable(Foo) in the second case is equivalent to: struct Foo { int x; private immutable(int[]) history; } You can't implicitly convert int[] to immutable(int[]) because whoever holds the original int[] reference can use it to change the data, which breaks the immutable guarantee of immutable(int[]). The only way this could work is if you made a copy of the int[]. So the library writer would have to provide a method for creating an immutable copy of the struct (like an .idup method or something). You may argue that this is bad because now user code is broken and you need to rewrite it to use .idup, but I'd argue that relying on implicit conversion to immutable already introduces a dependency on implementation details of Foo, which should be avoided in the first place if you want to have a clean encapsulation. I mean, given a Foo type exported by a library, if that type is meant to be an opaque type, then my code should make no assumptions about whether it can implicitly convert to immutable. I should rather require the library writer to provide an .idup method for creating an immutable instance of the struct than to blindly write the code to implicitly convert to immutable (thus introducing a hidden reliance on how Foo is implemented) and then have it broken later when the library writer changes its implementation. OTOH, if it's not an opaque type, then it's no surprise that changing its implementation should also require changing the code (that depends on its implementation details). So I don't see anything wrong with this particular scenario. What other scenarios were being considered? T -- He who does not appreciate the beauty of language is not worthy to bemoan its flaws.
Re: mutable, const, immutable guidelines
On Wednesday, 16 October 2013 at 19:06:06 UTC, Daniel Davidson wrote: I don't understand how it could be fine. As code grows it would lead to people not adding useful members like history just because of the huge repercussions. struct User { immutable(Foo) foos; } How can I as a user adapt to that change? Before the change assignment worked equally well among all of Mutable, Immutable, Const. After that change any `foos ~= createFoo(...)` would require change. And it is not clear what the change would be. I think any usage of immutable with types/entities not initially designed for immutability is an potential mistake and in that sense it is good that change has broken the user code. Same goes for operating on immutable entity in generic code as if it is a value type without actually checking it via introspection.
Re: Problem: Cannot create class out of nothing using witchcraft
Am 16.10.2013 21:02, schrieb DoctorCaptain: On Wednesday, 16 October 2013 at 14:08:52 UTC, Benjamin Thaut wrote: Am 16.10.2013 10:40, schrieb DoctorCaptain: http://dpaste.dzfl.pl/07b20d75 Note the use of typeof() to get the type of the elements at each index of members, to generate a type on which a constructor can be called to instantiate the elements at each index of members. Magic. There is actually a easier way to instanciate the elements. Just do new T[i](); no need for typeof. Thank you again for your excellent answers. I knew I shouldn't have posted my most recent response at two in the morning or whatever it was; when I woke up this morning I was thinking, I understand everything I was confused about last night, and I'm going to look silly to the fellas that answer my questions. Especially, pretty much the first thing I thought of when I opened my eyes this morning was I don't need to do typeof, I can index the type tuple, and now I look silly. I definitely knew that the T in the mixed-in class definition is the same as the variadic template parameter T in our GrabBagT template. My question, at the time, was geared towards, How in the world does it act like a tuple of types that we can just use? The answer to that is, painfully obviously, T is literally a tuple of types that we can just use, working exactly as intended. Hopefully the following is correct, as an exercise in making sure that my understanding is correct: Purely theoretically speaking (as in we're no longer talking about D specifically, but rather type theory in general), let's take the type int[]. Variables of type int[] can be created. Let's do this: int[] iarray; For some within-bounds index i, iarray[i] will yield a -value- whose -type- is int. Along these same lines (again in a go-with-me-here, theoretical sense), if we were to index the actual type int[], like int[i], then what is yielded at that index is the -type- int. int[] is a homogenous type tuple of some length, containing only the -type- int as an element at each of its indexes. Go with me here. This works perfectly well. At compile time, the compiler knows everything it needs to know about int[] in order to reason about how a variable of that type, like iarray, can behave. It knows that at every within-bounds index of iarray, it can be sure to find a value of type int, because int[] is a homogenous type tuple of the type int. In exactly this same way, T is also a type tuple. The only difference is, T can be (but by no means has to be) a heterogenous type tuple. That is, since we're instantiating these templates (that take T...) at compile time, all types contained within T are known at compile time, and can be reasoned about. So let's say we declare something like: T members; instantiated such that myTemplate(T...) is called like myTemplate!(int, float, bool) This means that, while at int[0] we can expect the -type- int, and at int[1] we can still expect the -type- int, at T[0] we expect the -type- int, at T[1] we expect the -type- float, and at T[2] we expect the -type- bool. So, at members[0], we can store a -value- of type int, at members[1] we can store a -value- of type float, and at members[2], we can store a -value- of type bool. The reason this is possible is because the compiler is aware of all of the types, and their order, in the type tuple T at compile time. The compiler can reason about the behavior of any index within members, because it can map that index within members back to the same index within T. As long as members[n] is treated as the type T[n], the compiler can reason about the behavior of a heterogenous array members, of type T. Correct? And again again again, thank you for your help. I never had type theory in university, but your explanation sounds reasonable and correct ;-) Kind Regards Benjamin Thaut
Re: Starting D with a project in mind.
I'm a very happy man ! Everything is built and working including dub and the http_server example from vibe.d. It's slow to build, but it executes quickly and strips down to about 3MB which is heavy but tolerable. Thanks to everybody for the help, now I can start learning D, exploring vibe.d and Pegged and hopefully make some good progress on my MUD. So to recap, to help anybody else building on ARM these are the steps I took :- mkdir gdc cd gdc wget http://gcc.igor.onlinedirect.bg/snapshots/LATEST-4.8/gcc-4.8-20131010.tar.bz2 tar xvf gcc-4.8-20131010.tar.bz2 git clone https://github.com/jpf91/GDC.git arm_gdc cd arm_gdc git checkout arm ./setup-gcc.sh ../gcc-4.8-20131010 cd ../ mkdir build cd build export C_INCLUDE_PATH=/usr/include/$(gcc -print-multiarch) export EXTRA_CONF=-mfloat-abi=hard --with-float=hard ../gcc-4.8-20131010/configure --enable-languages=d --disable-bootstrap --prefix=/usr/local/gdc --disable-multilib --disable-softfloat --with-float=hard make -j2 sudo make install sudo cp ../arm_gdc/libphobos/libdruntime/core/time.d /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core sudo mv /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di.old I don't know why that last step was necessary but dub and a few other things didn't build without it. After that dub built fine once I'd hacked the build file to use gdc.
Re: mutable, const, immutable guidelines
On Wednesday, 16 October 2013 at 19:01:59 UTC, H. S. Teoh wrote: On Wed, Oct 16, 2013 at 08:49:51PM +0200, Daniel Davidson wrote: On Wednesday, 16 October 2013 at 17:55:14 UTC, H. S. Teoh wrote: On Wed, Oct 16, 2013 at 07:23:24PM +0200, Daniel Davidson wrote: [...] If you have a type that has now or may ever have in the future any mutable aliasing (e.g. inclusion of T[] or T1[T1] where Ts are mutable) do not ever use the immutable keyword in any context as things just break down. Yes, because immutable means nothing, no one, can change the data after it's constructed, ever. If you want mutable aliasing, what you want is const, not immutable. I think the term mutable aliasing and what you want don't work together. mutable aliasing is not about context of usage or what you want, it is a compile time attribute of a struct. I want to use associative arrays in composition because I think they are the way I view and use my data. `struct T { string[string] i; }` has mutable aliasing, like it or not. So, it is not so much that I want mutable aliasing - in fact I fear it. But once you use AAs it is a fact of life. [...] Is the suggestion here: use immutable in any composition context where you have slices and you want to not worry about mutable aliasing. So, do like string does: any case where you have T[] as a member, prefer immutable(T)[] since then you don't have to worry about sharing. Well, not sure that works in general because the T in string is char and has no mutable aliasing itself. Suppose T itself has mutable aliasing, then what? Or, suppose it is a struct with no mutable aliasing *now*. Who's to say it won't change. So, where does all this leave us w.r.t. a good set of guidelines? Sorry, I kinda barged into this conversation, so I'm not sure what exactly you're trying to achieve here. What kind of composition contexts do you have in mind? Maybe you could help me understand what you're trying to do? Thanks. I appreciate any help I can get. Here is a small sample: http://pastebin.com/TeiQ9DYa Other samples have at least 5 levels of composition. I'm generating the structure from json schema so I'm looking for something that scales and is immune to changes in deeply nested members. Keeping in mind that AA's, as they are currently implemented, leaves a lot of room for improvement, to say the least. So you might be running into some AA-related issues, not the type system proper. I understand. It is a shame. If the data source is rich json data - I think AAs are a necessity.
Re: Starting D with a project in mind.
On Wednesday, 16 October 2013 at 19:18:53 UTC, Andrew wrote: I'm a very happy man ! Everything is built and working including dub and the http_server example from vibe.d. It's slow to build, but it executes quickly and strips down to about 3MB which is heavy but tolerable. Thanks to everybody for the help, now I can start learning D, exploring vibe.d and Pegged and hopefully make some good progress on my MUD. So to recap, to help anybody else building on ARM these are the steps I took :- mkdir gdc cd gdc wget http://gcc.igor.onlinedirect.bg/snapshots/LATEST-4.8/gcc-4.8-20131010.tar.bz2 tar xvf gcc-4.8-20131010.tar.bz2 git clone https://github.com/jpf91/GDC.git arm_gdc cd arm_gdc git checkout arm ./setup-gcc.sh ../gcc-4.8-20131010 cd ../ mkdir build cd build export C_INCLUDE_PATH=/usr/include/$(gcc -print-multiarch) export EXTRA_CONF=-mfloat-abi=hard --with-float=hard ../gcc-4.8-20131010/configure --enable-languages=d --disable-bootstrap --prefix=/usr/local/gdc --disable-multilib --disable-softfloat --with-float=hard make -j2 sudo make install sudo cp ../arm_gdc/libphobos/libdruntime/core/time.d /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core sudo mv /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di.old I don't know why that last step was necessary but dub and a few other things didn't build without it. After that dub built fine once I'd hacked the build file to use gdc. Cool. I was posting in the D.GNU newsgroup about this when I noticed your update, so I included a link to this work around in my post [1]. Maybe Iain or any of the other gurus know of a better way, because the last part looks awfully dirty :-D [1] http://forum.dlang.org/post/wshaxsawkvkwfaefp...@forum.dlang.org
Re: UDAs on templates
On 2013-10-16 16:05, Max Samukha wrote: That sucks. Then, getAttributes (and other traits dealing with overload sets) should return an empty set, a union or accept a pattern to match against the members of the overload set. Currenrly one need to call __traits(getOverloads) and then iterate of the result and call __traits(getAttributes) on each item. -- /Jacob Carlborg
Re: Starting D with a project in mind.
On Wednesday, 16 October 2013 at 19:18:53 UTC, Andrew wrote: I'm a very happy man ! Everything is built and working including dub and the http_server example from vibe.d. It's slow to build, but it executes quickly and strips down to about 3MB which is heavy but tolerable. Thanks to everybody for the help, now I can start learning D, exploring vibe.d and Pegged and hopefully make some good progress on my MUD. So to recap, to help anybody else building on ARM these are the steps I took :- mkdir gdc cd gdc wget http://gcc.igor.onlinedirect.bg/snapshots/LATEST-4.8/gcc-4.8-20131010.tar.bz2 tar xvf gcc-4.8-20131010.tar.bz2 git clone https://github.com/jpf91/GDC.git arm_gdc cd arm_gdc git checkout arm ./setup-gcc.sh ../gcc-4.8-20131010 cd ../ mkdir build cd build export C_INCLUDE_PATH=/usr/include/$(gcc -print-multiarch) export EXTRA_CONF=-mfloat-abi=hard --with-float=hard ../gcc-4.8-20131010/configure --enable-languages=d --disable-bootstrap --prefix=/usr/local/gdc --disable-multilib --disable-softfloat --with-float=hard make -j2 sudo make install sudo cp ../arm_gdc/libphobos/libdruntime/core/time.d /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core sudo mv /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di /usr/local/gdc/include/d/4.8.2/armv7l-unknown-linux-gnueabihf/core/time.di.old I don't know why that last step was necessary but dub and a few other things didn't build without it. After that dub built fine once I'd hacked the build file to use gdc. This is very cool. You should add it to the wiki so it doesn't get lost: http://wiki.dlang.org
Re: mutable, const, immutable guidelines
On Wed, Oct 16, 2013 at 09:06:05PM +0200, Daniel Davidson wrote: On Wednesday, 16 October 2013 at 18:52:23 UTC, qznc wrote: [...] Library code: struct Foo { int x; } User code: Foo f; immutable f2 = f; This works, even though the library writer might not have anticipated that someone makes Foo immutable. However, now the library writer obliviously releases a new version of the library, which extends it like this: struct Foo { int x; private int[] history; } Unfortunately, now the user code is broken due to the freshly introduced mutable aliasing. Personally, I think is fine. Upon compilation the user code gives a error message and user developer can adapt to the code to the new library version. Some think the library writer should have a possibility to make this work. I don't understand how it could be fine. As code grows it would lead to people not adding useful members like history just because of the huge repercussions. struct User { immutable(Foo) foos; } How can I as a user adapt to that change? Before the change assignment worked equally well among all of Mutable, Immutable, Const. After that change any `foos ~= createFoo(...)` would require change. And it is not clear what the change would be. The root of the problem is reliance on assignment between mutable / immutable / const. This reliance breaks encapsulation because you're making an assumption about the assignability of a presumedly opaque library type to immutable / const. In D, immutable is *physical* immutability, not logical immutability; by writing immutable(Foo) you're saying that you wish to have physically-immutable instances of Foo. However, whether this is possible depends on the implementation details of Foo, which, if Foo is supposed to be an opaque type, breaks encapsulation. Without knowing how Foo is implemented (and user code shouldn't know that), you can't reliably go around and claim Foo can be made immutable from a mutable instance. The fact that you're relying on Foo being implicitly convertible to immutable(Foo) means you're already depending on implementation details of Foo, and should be prepared to change code when Foo's implementation changes. If you want to say that User cannot modify the Foo's it contains, you should use const rather than immutable. It is safe to use const because anything is implicitly convertible to const, so it doesn't introduce any reliance upon implementational details of Foo. If you insist on being able to append to immutable(Foo)[], then you'll need a createFoo method that returns immutable instances of Foo: struct User { immutable(Foo)[] foos; } immutable(Foo) createFoo(...) { ... } User u; u.foos ~= createFoo(...); // now this works The problem with this, of course, is that it unnecessarily restricts createFoo(): if you want *mutable* instances of Foo, then you can't use this version of createFoo(), but have to create another function that probably does exactly the same thing. So an alternative solution is to use Phobos' assumeUnique template: struct User { immutable(Foo)[] foos; } Foo createFoo(...) { ... } User u; u.foos ~= assumeUnique(createFoo(...)); The assumeUnique template basically does a cast from mutable to immutable, but explicitly documents the purpose of this cast in the code. It places the onus on the user to ensure that the Foo returned by createFoo is actually unique. If not, you break the type system and the immutability guarantee may no longer hold. To illustrate why adding mutable aliases to Foo *should* break code, consider this: /* This is what Foo looked like before: struct OriginalFoo { int x; } */ /* This is what Foo looks like now */ struct Foo { int x; private int[] history; void changeHistory() { history[0]++; } } Foo createFoo(int x) { Foo f; f.x = x; f.history = [1]; } Foo f = createFoo(); immutable(Foo) g = f; // doesn't compile, but suppose it does f.changeHistory();// oops, g.history has mutated, so it's // *not* immutable after all That's why assigning f to g must be made illegal, since it breaks immutability guarantees. OTOH, if you absolutely have to do it, you can document your intent thus: Foo f = createFoo(); immutable(Foo) g = assumeUnique(f); // Now if you use f to mutate g, it's your own problem: you // claimed that g was unique but actually it isn't. So it's your // own fault when your supposedly-immutable Foo mutates. // If you *don't* do stupid things, OTOH, this lets your code // continue to work when the library writer decides to change // Foo's implementation to
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 17:50:48 UTC, Daniel Davidson wrote: How do you propose to make a mutable copy *generically*? You can't. Let alone generically. If I give you an immutable int* p, how do you copy it to int* p ? On Wednesday, 16 October 2013 at 18:11:48 UTC, Daniel Davidson wrote: Thanks. It is cute - but not so helpful. The example stands. I *need* to call a createRFromT. Their shapes are the same in this simple example because I simplified. Make R look like: struct R { string[string] ss; int[] j; } and the cute trick falls apart. In words, I have an R and I want to make a T. The R is const the T will be immutable because the ctor requires it. But it is technically not immutable until it is initialized. The problem is that you are taking a const(R). And you can't assign a const to an immutable. It has nothing to do with initialization. Remember: const means *you* promise not to modify the value, whereas immutable means *no one* will modify it ever. Because of this, you can't assign a const to an immutable. For example: int[] a = [1]; const(int)[] c = a; //Legal immutable(int)[] i = c; //Forbidden If that assignment passed, think of what would happen if I wrote: a[0] = 5; On Wednesday, 16 October 2013 at 18:14:22 UTC, Daniel Davidson wrote: I agree with the sentiment. But as it stands I think a copy should not be necessary. I could make a local mutable R, pass it to createRFromT to get it initialized and then copy it back somehow to the member variable r. That to me is silly. The copy should not be required. A copy *might* not be necessary provided building an immutable copy from mutable is actually legal. This is not your case. What you are doing is warping the type system.
Re: mutable, const, immutable guidelines
On Wednesday, 16 October 2013 at 19:12:48 UTC, Dicebot wrote: On Wednesday, 16 October 2013 at 19:06:06 UTC, Daniel Davidson wrote: I don't understand how it could be fine. As code grows it would lead to people not adding useful members like history just because of the huge repercussions. struct User { immutable(Foo) foos; } How can I as a user adapt to that change? Before the change assignment worked equally well among all of Mutable, Immutable, Const. After that change any `foos ~= createFoo(...)` would require change. And it is not clear what the change would be. I think any usage of immutable with types/entities not initially designed for immutability is an potential mistake and in that sense it is good that change has broken the user code. Same goes for operating on immutable entity in generic code as if it is a value type without actually checking it via introspection. I don't disagree. Now, what does it mean to initially design for immutability and what are the guidelines. I thought that was kind of what we were talking about here. How to effectively use const and immutable. If the rule is - don't use immutable unless you have immutability in mind for your design, ok. Maybe take it a step further... How about this - show a good use of immutable in any context where mutable aliasing (e.g. AAs) are in the mix. If the response is there are none, it is just too hairy of a proposition then something is wrong. One general idea that was presented by Ali is that an immutable parameter means that not only are you guaranteeing that you will not change your data, but also that no one else, even in another thread will. That sounds appealing. After all, who doesn't want the data they are using in a function to not change from underneath them? Suppose you have highly structured, deeply nested reference data you read from a nosql DB. Surely there is opportunity and some benefit to use immutable? The result of the query is just a read only data source. But then that data will be consumed - presumably by functions with either immutable or const parameters. If all signatures use const then when can you benefit from the fact that the data is really immutable (by the time it gets to a function with const parm the fact that it really was/is immutable is lost.
Re: this() immutable
On 2013-10-16, 18:54, Daniel Davidson wrote: On Thursday, 13 June 2013 at 12:29:57 UTC, Simen Kjaeraas wrote: On Thu, 13 Jun 2013 14:17:22 +0200, Stephan Schiffels stephan_schiff...@mac.com wrote: For example, is there a way of instantiating an object normally (i.e. mutable), and then later freeze it to immutable via a simple cast or so? In std.exception there is assumeUnique. It's basically just a cast, but might be good enough for you. Is there any other recourse here? Why does making `this(...) immutable` fix things below? Shouldn't that immutable designation mean no members of this will be modified? But that is the whole point of an initializer? Why does immutable make sense in this context at all? Immutable in the case of constructors means that the instance will be created using only data implicitly castable to immutable. That way, when construction is finished, it is safe for the type system to mark the result as immutable. My problem is a bit more elaborate and unfortunately to initialize members I need to call standard functions that have not been made pure (but should be). If you're calling functions that are not marked pure in order to create immutable data, you will need to cast to immutable afterwards. If you know this is safe, no problem. It would benefit us all if you reported these functions or created a pull request for Phobos, of course. -- Simen
Re: this() immutable
On Wednesday, 16 October 2013 at 19:55:41 UTC, Simen Kjaeraas wrote: On 2013-10-16, 18:54, Daniel Davidson wrote: On Thursday, 13 June 2013 at 12:29:57 UTC, Simen Kjaeraas wrote: On Thu, 13 Jun 2013 14:17:22 +0200, Stephan Schiffels stephan_schiff...@mac.com wrote: For example, is there a way of instantiating an object normally (i.e. mutable), and then later freeze it to immutable via a simple cast or so? In std.exception there is assumeUnique. It's basically just a cast, but might be good enough for you. Is there any other recourse here? Why does making `this(...) immutable` fix things below? Shouldn't that immutable designation mean no members of this will be modified? But that is the whole point of an initializer? Why does immutable make sense in this context at all? Immutable in the case of constructors means that the instance will be created using only data implicitly castable to immutable. That way, when construction is finished, it is safe for the type system to mark the result as immutable. My problem is a bit more elaborate and unfortunately to initialize members I need to call standard functions that have not been made pure (but should be). If you're calling functions that are not marked pure in order to create immutable data, you will need to cast to immutable afterwards. If you know this is safe, no problem. I'm in the learn news group for a reason. I think what you say makes sense - a cast is required. But perhaps you have more confidence that there is no problem. You and dicebot surely disagree on this practice as he sees no real reason to ever circumvent the type system. It would benefit us all if you reported these functions or created a pull request for Phobos, of course. I reported my issue with the `chain` function to this NG and tried to start annotating items used by chain with pure to see how far the thread led. Honestly it was quickly clear that it led too far for me to follow it and someone else indicated the problem had to do with Voldermort types. If there is more I could do to benefit us all, beyond learning how it works and what to avoid in my own code - I will be glad to try.
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 19:49:25 UTC, monarch_dodra wrote: On Wednesday, 16 October 2013 at 17:50:48 UTC, Daniel Davidson wrote: How do you propose to make a mutable copy *generically*? You can't. Let alone generically. If I give you an immutable int* p, how do you copy it to int* p ? That was my point. On Wednesday, 16 October 2013 at 18:11:48 UTC, Daniel Davidson wrote: Thanks. It is cute - but not so helpful. The example stands. I *need* to call a createRFromT. Their shapes are the same in this simple example because I simplified. Make R look like: struct R { string[string] ss; int[] j; } and the cute trick falls apart. In words, I have an R and I want to make a T. The R is const the T will be immutable because the ctor requires it. But it is technically not immutable until it is initialized. The problem is that you are taking a const(R). And you can't assign a const to an immutable. It has nothing to do with initialization. No I don't think I am. What code are you looking at? A copy *might* not be necessary provided building an immutable copy from mutable is actually legal. This is not your case. What you are doing is warping the type system. Based on your previous comment, I don't think you understood the setup.
Re: does cast make an lvalue appear to be an rvalue
On Wednesday, 16 October 2013 at 19:49:25 UTC, monarch_dodra wrote: On Wednesday, 16 October 2013 at 17:50:48 UTC, Daniel Davidson wrote: How do you propose to make a mutable copy *generically*? You can't. Let alone generically. If I give you an immutable int* p, how do you copy it to int* p ? On Wednesday, 16 October 2013 at 18:11:48 UTC, Daniel Davidson wrote: Thanks. It is cute - but not so helpful. The example stands. I *need* to call a createRFromT. Their shapes are the same in this simple example because I simplified. Make R look like: struct R { string[string] ss; int[] j; } and the cute trick falls apart. In words, I have an R and I want to make a T. The R is const the T will be immutable because the ctor requires it. But it is technically not immutable until it is initialized. The problem is that you are taking a const(R). And you can't assign a const to an immutable. It has nothing to do with initialization. Just to clarify: in the code below: createRFromT(t, r) is *not* meant to imply it will just try an assignment. Rather, it reads from t and builds its own data for R. The problem is with initialization - see Simen Kjaeraas response here: http://forum.dlang.org/post/mailman.2241.1381953340.1719.digitalmars-d-le...@puremagic.com struct S { R r; this(ref const(T) t) immutable { createRFromT(t, r); } } void createRFromT(ref const(T) t, ref R r) { //... }
Re: mutable, const, immutable guidelines
On Wed, Oct 16, 2013 at 09:45:09PM +0200, Daniel Davidson wrote: On Wednesday, 16 October 2013 at 19:12:48 UTC, Dicebot wrote: [...] I think any usage of immutable with types/entities not initially designed for immutability is an potential mistake and in that sense it is good that change has broken the user code. Same goes for operating on immutable entity in generic code as if it is a value type without actually checking it via introspection. I don't disagree. Now, what does it mean to initially design for immutability and what are the guidelines. I thought that was kind of what we were talking about here. How to effectively use const and immutable. I'd say that user code should use const, not immutable (unless the library provides a way of constructing immutable instances of the type, of course), because immutable makes assumptions about implementation details, which should not be known unless you break encapsulation. As a user of a properly encapsulated type, I can't make any guarantees about its immutability; the best I can do is to promise I don't change it myself -- i.e., const. Immutable should be used in library code to provide strong guarantees to the user: since you're the one responsible for implementing the type, you're in the position to make guarantees about its uniqueness (and hence, immutability). [...] One general idea that was presented by Ali is that an immutable parameter means that not only are you guaranteeing that you will not change your data, but also that no one else, even in another thread will. That sounds appealing. After all, who doesn't want the data they are using in a function to not change from underneath them? I'm actually wary of this view, to be honest. An immutable parameter means you expect your *caller* to provide you with a value that cannot be changed, not by you, nor by anybody else, ever. Sure, it's nice to have, but that imposes a rather high bar on your callers. They have to be responsible to guarantee that whatever they hand to you cannot be changed by anything or anyone else, at any time. If they can do this, then great; if not, they won't be able to call your function. Suppose you have highly structured, deeply nested reference data you read from a nosql DB. Surely there is opportunity and some benefit to use immutable? The result of the query is just a read only data source. But then that data will be consumed - presumably by functions with either immutable or const parameters. If all signatures use const then when can you benefit from the fact that the data is really immutable (by the time it gets to a function with const parm the fact that it really was/is immutable is lost. I'm of the view that code should only require the minimum of assumptions it needs to actually work. If your code can work with mutable types, then let it take a mutable (unqualified) type. If your code works without modifying input data, then let it take const. Only if your code absolutely will not work correctly unless the data is guaranteed to never change, ever, by anyone, should it take immutable. I'm not sure what benefits you get from requiring immutable when the code doesn't really need to depend on immutability. It just makes the code harder to use (you have to make sure whatever you pass to it is immutable, and sometimes that's not easy to guarantee, and would require a lot of copying). Immutable only benefits you when the code *can't* work correctly unless the data is guaranteed never to change, ever. Hash table keys come to mind -- if you compute the hash value of the key and use that to determine which slot to put the data into, it would be very bad if somebody else mutated that key via a mutable reference after the fact -- now your AA is broken because the hash value no longer matches the key. By requiring an immutable key, you ensure that this never happens. Note that in D, everything is thread-local by default unless explicitly made shared, so using immutable to guarantee other threads won't mutate the data isn't really necessary. T -- What do you mean the Internet isn't filled with subliminal messages? What about all those buttons marked submit??
Re: this() immutable
On Wednesday, 16 October 2013 at 20:09:51 UTC, Daniel Davidson wrote: You and dicebot surely disagree on this practice as he sees no real reason to ever circumvent the type system. There are some cases were you have no other options because of language design limitations but it is something that should be done only by experienced D developers who clearly understand the impact upon the generated machine code and hidden behind the library functions. Not a casual casts in user code by any means.
Re: this() immutable
On Wed, Oct 16, 2013 at 10:09:50PM +0200, Daniel Davidson wrote: [...] I reported my issue with the `chain` function to this NG and tried to start annotating items used by chain with pure to see how far the thread led. Honestly it was quickly clear that it led too far for me to follow it and someone else indicated the problem had to do with Voldermort types. If there is more I could do to benefit us all, beyond learning how it works and what to avoid in my own code - I will be glad to try. Hmm. I just did a quick-n-dirty change to Phobos, and it seems to make chain() usable with pure code. I'm not sure why the compiler didn't infer pure for it -- it should. (Or perhaps I'm missing something obvious -- I didn't run the Phobos unittest so maybe the following change breaks something.) - In the Phobos source, edit std/range.d and look for the function `auto chain(Ranges...)(Ranges rs)` (around line 2022 or thereabouts), then the struct Result inside this function. - Find the ctor for this struct (circa line 2074), and annotate it with pure. - Now the following code compiles: import std.range; auto pureFunc() pure { return chain([1,2,3], [2,3,4]); } void main() { auto r = pureFunc(); } This is just a hack, of course. The compiler *should* be able to correctly infer that the ctor is pure. So the real fix is to find out why the compiler isn't doing that. T -- Leather is waterproof. Ever see a cow with an umbrella?
Re: this() immutable
On Wednesday, October 16, 2013 14:10:02 H. S. Teoh wrote: This is just a hack, of course. The compiler *should* be able to correctly infer that the ctor is pure. So the real fix is to find out why the compiler isn't doing that. Because it sucks at attribute inference. The inference that it does right now is very shallow: http://d.puremagic.com/issues/show_bug.cgi?id=10329 The compiler could use a considerable improvements with regards to how much inference it's doing for templated stuff. Without it, the attribute inference for Phobos is nowhere near good enough. - Jonathan m Davis
Re: this() immutable
On Wed, Oct 16, 2013 at 02:10:02PM -0700, H. S. Teoh wrote: On Wed, Oct 16, 2013 at 10:09:50PM +0200, Daniel Davidson wrote: [...] I reported my issue with the `chain` function to this NG and tried to start annotating items used by chain with pure to see how far the thread led. Honestly it was quickly clear that it led too far for me to follow it and someone else indicated the problem had to do with Voldermort types. If there is more I could do to benefit us all, beyond learning how it works and what to avoid in my own code - I will be glad to try. Hmm. I just did a quick-n-dirty change to Phobos, and it seems to make chain() usable with pure code. I'm not sure why the compiler didn't infer pure for it -- it should. (Or perhaps I'm missing something obvious -- I didn't run the Phobos unittest so maybe the following change breaks something.) [...] Actually, I just remembered why. It's because attribute inference only happens for the template function itself, but not for any nested structs or struct members. Arguably, the compiler should also do inference for all nested declarations in a template too. Do you have a bugzilla ticket for this issue? I'd like to add my findings to it. Thanks! T -- Without geometry, life would be pointless. -- VS
Questions about VisualD
I've clicked on Build Phobos browse info and now I have absolute no idea how I can restore my old class view for my current project. Any suggestions? And it seems that VisualD ignores all of my Tasks. My Tasklist is always empty, whats wrong? Or is this not implemented?
Can I compile for Linux from a Windows platform?
Basically I want to develop a program on Windows and send the exe to someone to use on a Linux platform. Is this possible?
Re: Can I compile for Linux from a Windows platform?
On Thursday, October 17, 2013 02:58:50 Stephen Jones wrote: Basically I want to develop a program on Windows and send the exe to someone to use on a Linux platform. Is this possible? AFAIK, it's not possible. It _might_ be possible to do with mingw and gdc or ldc (I don't know if they use mingw or not, though I'd guess that they do), but even if you _could_ target Linux with that (which I doubt), the versions of the libraries the program was built against wouldn't match what would be found on a Linux box, so it wouldn't actually run on any Linux box. I've heard of building on Linux for mingw and then running it on Windows, but that's it, and I think that it's pretty surprising that that works. In general, you can't cross-compile across operating systems. - Jonathan M Davis
Function pointer to member function.
I would like to get access to a member function pointer. Taking the this* as the first argument. class Foo { void bar(int a) { //do something awesome } } unittest { Foo a = new Foo(); Foo b = new Foo(); auto fp = getFP!(Foo.bar); fp(a, 1); //Basically calls a.foo(1) fp(b, 1); //Basically calls b.foo(1) } How should i implement getFP above? Is it even possible?
Re: Can I compile for Linux from a Windows platform?
On Thursday, 17 October 2013 at 01:18:42 UTC, Jonathan M Davis wrote: In general, you can't cross-compile across operating systems. Linux to Windows is pretty easy. You can just run the Windows version of dmd under wine on linux to make exes, or you can compile gcc (and presumably gdc, though I've never tried) for linux to make exes. I'm sure similar techniques could be used, in theory at least, to do Windows to Linux, but I've never seen it done and you're absolutely right about the versions not matching up. Hell, it is hard enough to get a binary from one linux box working on another linux box!
Re: Can I compile for Linux from a Windows platform?
On Thu, Oct 17, 2013 at 04:24:07AM +0200, Adam D. Ruppe wrote: On Thursday, 17 October 2013 at 01:18:42 UTC, Jonathan M Davis wrote: In general, you can't cross-compile across operating systems. Linux to Windows is pretty easy. You can just run the Windows version of dmd under wine on linux to make exes, or you can compile gcc (and presumably gdc, though I've never tried) for linux to make exes. I'm sure similar techniques could be used, in theory at least, to do Windows to Linux, but I've never seen it done and you're absolutely right about the versions not matching up. Hell, it is hard enough to get a binary from one linux box working on another linux box! Linux is rather heavy on the compile-from-source philosophy. Distributing binaries in Linux is fraught with peril and generally not done, except by distro vendors (who actually have a fighting chance of getting it right) and companies who are paranoid about distributing source (who generally *don't* get it right, thus are unable to reach a significant proportion of the Linux market). T -- Computers aren't intelligent; they only think they are.
Re: Function pointer to member function.
On Thursday, 17 October 2013 at 01:17:21 UTC, TheFlyingFiddle wrote: I would like to get access to a member function pointer. Taking the this* as the first argument. ...snip... How should i implement getFP above? Is it even possible? Well, it's certainly possible. If you were to do this: ``` delegate void(int) dg = a.bar; dg(1); ``` then you'd see the behavior you're looking for. Basically the class reference is stored in dg.ptr and the function is in dg.funcptr. With that in mind, I whipped this up: ``` import std.stdio; class Foo { char c; this() { c = 'a'; } this(char _c) { c = _c; } void bar(int i) { writeln(i = , i, c = , c); } } import std.traits; //ParentOf!S is pseudocode representing __traits(parent, S) //ReturnType!S function(ParentOf!S, ParameterTypeTuple!S) auto getFP(alias S)() if(isSomeFunction!S) { mixin(alias Parent = ~ __traits(parent, S).stringof ~ ;); return (Parent r, ParameterTypeTuple!S t) { ReturnType!S delegate(ParameterTypeTuple!S) dg; dg.funcptr = S; dg.ptr = cast(void*) r; return dg(t); }; } void main() { Foo a = new Foo(); Foo b = new Foo('b'); auto fp = getFP!(Foo.bar); fp(a, 1); fp(b, 2); } ``` Now one thing to note is that I'm not confident it's bug-free. It does work in this test case, but I couldn't use __traits(parent, S) as a type, so I used a mixin to kind of force it to work. So I'm not fully sure whether it will work in all cases, but if someone else has some improvements, that's fine. Another thing: I didn't spend too much time on the template constraint. isSomeFunction is almost certainly too permissive. I just threw it together and I haven't coded in D for a while. I hope this helped!
Re: Can I compile for Linux from a Windows platform?
If you want to play within a Linux environment on Windows, you can try CygWIN: http://www.cygwin.com/ On 17/10/13 04:24, Adam D. Ruppe wrote: On Thursday, 17 October 2013 at 01:18:42 UTC, Jonathan M Davis wrote: In general, you can't cross-compile across operating systems. Linux to Windows is pretty easy. You can just run the Windows version of dmd under wine on linux to make exes, or you can compile gcc (and presumably gdc, though I've never tried) for linux to make exes. I'm sure similar techniques could be used, in theory at least, to do Windows to Linux, but I've never seen it done and you're absolutely right about the versions not matching up. Hell, it is hard enough to get a binary from one linux box working on another linux box!