Re: Simple performance question from a newcomer
On Monday, 22 February 2016 at 07:10:23 UTC, Kapps wrote: If you do want to test the differences between the range approach and the loop approach, something like: auto sumtest4(Range)(Range range) @safe pure { return range.reduce!((a, b) => a + b); } is a more fair comparison. I get results within 15% of sumtest2 with this using dmd. I think with ldc this would be identical, but the version in homebrew is too old to compile this. Using LDC with the mir version of ndslice so it compiles, and the following code: sw.reset(); sw.start(); foreach (unused; 0..times) { for (int i=0; i a + b); } I get: 145 ms 19 ms 19 ms 19 ms So, with LDC, there is no performance hit doing this. The only performance hit is when .sum uses a different algorithm for a more accurate result. Also, the LDC version appears to be roughly 5x faster than the DMD version.
Re: Simple performance question from a newcomer
If you do want to test the differences between the range approach and the loop approach, something like: auto sumtest4(Range)(Range range) @safe pure { return range.reduce!((a, b) => a + b); } is a more fair comparison. I get results within 15% of sumtest2 with this using dmd. I think with ldc this would be identical, but the version in homebrew is too old to compile this.
Re: vk.xml
On Sunday, 21 February 2016 at 15:18:44 UTC, ZombineDev wrote: On Sunday, 21 February 2016 at 12:52:33 UTC, Nicholas Wilson wrote: So I was going through the vulcan spec to try to create a better D bindings for it. (pointer /len pairs to arrays adhering to D naming conventions and prettying up the *Create functions functions like vkResult *Create( arg ,&arg, retptr) to a fancy throw on misuse struct with constructors and that kind of stuff.) the structure of the registry is as follows. struct KHR_registry { } I'm glad to see more people looking to create a D binding from vk.xml! I was also working on this (http://forum.dlang.org/post/ygylvtuwwiwyqtcnl...@forum.dlang.org), unfortunately I won't be able to continue my work until early March, so I hope you'll do a good job in the mean time ;) Unfortunately the spec is written in a very C specific way so we need to have a bunch of special cases for parsing the C code that's interleaved with the XML tags. I haven't used std.xml yet, but I hope I may be able to help you. where "string content" is the string between the tags (does this have a name?) and thing with @Tag are always in the tag (although it is also inconsistent). I tried looking at the docs for std.xml but they were not very helpful. May be you can use http://dlang.org/phobos/std_xml#.Element.text in combination with http://dlang.org/phobos/std_xml#.Element.elements To further complicate things not all of the fields are present in all cases also I need to keep track of the number of '*' (see fields named indirections) after a tag has closed for pointer type declarations in function signatures and structs. You mean things like: void** ppData (from the vkMapMemory command) ? Yeah this is extremely ugly. One way to do it is to go to the "param" XML element and check if the size of it's elements matches it's text size. In the case above everything between and is 39 characters and the two tags are 17 and 19 character respectively (total 36) which leaves 3 chars for the indirections. If we make a pass to remove all whitespace between tags (between ">" and "<") we should get exactly 2 characters which is the number of indirection we're looking for. Another way is to just strip the tags and leave only their internal text. In the above example the result should be: void** ppData which is valid D code and we can leave it that way for now. Also is there a way to do sane cross referencing without having internal pointers everywhere. I am no XML expert (so there may be an easier way), but I think it would be easier if we use associative arrays, instead of plain arrays. That way we can check for example: if ("VkBuffer" in types && "VkDevice" in types) types["VkBuffer"].parent = types["VkDevice"]; I'm sure there should be a very elegant way to do this by recursing down through the sub-structs The simplest solution, IMO, is to insert all the types, commands, enums, etc. in associative arrays first and then do cross-referencing. E.g. Type[string] types; struct Type { // ... other members // Set to string first, and later change // to the proper Type, after the whole `types` table has been read. Algebraic(string, Type*) parent; // ... more members } Otherwise the only sane way to do forward reference resolution is to use D Fibers. I have used fibers in some of my projects, but the extra complications are not worth it for this task as the xml is only 5100 lines and the performance benefits probably would not be very large. Many thanks Nic BTW if you run into some other issues with std.xml, you can also check http://arsdnet.net/web.d/dom.html and https://github.com/burner/std.xml2 Also don't forget to use unittests extensively! Thanks for the tips. I used AA and just got it to compile! :) :| :( but fails to link. Undefined symbols for architecture x86_64: "_D28TypeInfo_xC4arsd3dom7Element6__initZ", referenced from: _D29TypeInfo_AxC4arsd3dom7Element6__initZ in app.o "_D4arsd3dom12__ModuleInfoZ", referenced from: _D3app12__ModuleInfoZ in app.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) --- errorlevel 1 any Ideas? structure is app.d app.o arsd/ dom.d dom.o --- CODE --- struct KHR_registry { string comment; // Not as xml comment but a ... struct vendorid { string name; string id; string comment; } vendorid[] vendorids; struct tag { string name; string author; string contact; } tag[] tags; struct validity_type// does not appear at this level but is common to commands and types { string[] str; } struct type { string name;// inconsistanly in tag and content string requires; string parent;
Re: Enforcing checks for return code
On Thursday, 18 February 2016 at 10:46:03 UTC, Marc Schütz wrote: On Thursday, 18 February 2016 at 07:21:05 UTC, Chris Katko wrote: [...] As Jonathan said, there's no such built-in feature, and exception are preferred over return codes. However, you can implement such a check at run time: [...] Thank you all for your insight. I think I have all the information I need.
Re: immutable class can't override opEquals, workaround?
On Sunday, 21 February 2016 at 07:58:42 UTC, Jonathan M Davis wrote: opEquals still works with const and immutable if it's legal to use a class as the key in an AA, it's a bug have a working version of the PR hasn't even been looked at yet from what I can tell, and it's the simplest of the bits that need to be done Thanks for the detailed overview. Judging from the source comment at hack-casting const to mutable, naive improvements affect much more code than I have imagined. The problem and possible solutions are on the radar still, that's satisfying. I understand if it takes more time, even if I too deem it important. -- Simon
Re: compilation issues (dmd, rdmd, ldc2)
On 21.02.2016 22:51, kraxli wrote: On Sunday, 21 February 2016 at 21:35:55 UTC, anonymous wrote: [...] a) do it the linker way: `dmd -L-L~/.dub/packages/consoled-1.0.0/ -L-lconsoled ...`, or b) do it the dmd way: `dmd ~/.dub/packages/consoled-1.0.0/libconsoled.a ...`. b) works! :-) Many thanks!! a) doesn't work, I need to search for more information on linking as I would like to understand these kind of basics in D :-). The books I consulted so far (Learn D and D cookbook) did not help me to understand the linking so far ... I investigated a bit on option a. The tilde (~) is the problem. Tilde expansion is only done when it's the first character of a word. So you either have to replace the tilde with "/home/foo", or somehow make it the first character of a word for the shell. Since you can't just put a space there, you would have to hack around a bit. For example: dmd -L-L`echo ~`/.dub/packages/consoled-1.0.0/ ... Regarding learning about linking: dmd's -L flag just forwards its argument to the linker. The linker isn't D-specific. To learn about linking in D you can learn about compiling/linking in general (what's a compiler, what's a linker, what's an object file, etc.), and you can learn about the command line interface of the specific linker that dmd invokes. On Ubuntu, dmd calls gcc for linking, which in turn calls ld. So if you want to know what to put into those -L arguments, you have to learn the gcc/ld command lines.
Re: Template this parameter in constructor
On 02/21/2016 01:48 PM, Steven Schveighoffer wrote: > So it follows that the template this type will be the next derived > constructor (or the type itself if that is the most derived type), I've just checked: Adding a C4 to the interitance chain (and constructing a C4) confirms that to be the case: C4 constructor: C4 C3 constructor: C4 C2 constructor: C3 C1 constructor: C2 Ali
Re: compilation issues (dmd, rdmd, ldc2)
On Sunday, 21 February 2016 at 21:51:27 UTC, kraxli wrote: a) doesn't work, I need to search for more information on linking as I would like to understand these kind of basics in D :-). The books I consulted so far (Learn D and D cookbook) did not help me to understand the linking so far ... I didn't go much into it in D Cookbook since I don't use libraries like this... the easiest way IMO is to forget the -I switch exists, don't use it, and don't mess with .lib/.a files at all either. Just pass all the source files to the compiler together so like: dmd yourprogram.d /path/to/consoled/consoled.d and it will all just work because then the compiler knows where the module is (thus obviating -I) and can compile the source on-demand (thus skipping the library linking). But if you don't do it this way, linking is just getting all the *compiled* code together, whereas the -I think is just about getting all the *imported source* together. When you import something, the compiler reads the declarations for a module, but does not necessarily generate code for it. Linking links the generated code for the different modules together.
Re: compilation issues (dmd, rdmd, ldc2)
On Sunday, 21 February 2016 at 21:35:55 UTC, anonymous wrote: On Sunday, 21 February 2016 at 21:21:30 UTC, kraxli wrote: Thanks for coming back on that! The problem is the consoled-package which has the library: ~/.dub/packages/consoled-1.0.0/libconsoled.a So I link it (or aim to do it ;-) ) but dmd cannot find it: $ dmd -I~/.dub/packages/consoled-1.0.0/source -L-l~/.dub/packages/consoled-1.0.0/libconsoled appX.d /usr/bin/ld: cannot find -l~/.dub/packages/consoled-1.0.0/libconsoled collect2: error: ld returned 1 exit status --- errorlevel 1 I don't think it works like that. If I remember correctly, you can either a) do it the linker way: `dmd -L-L~/.dub/packages/consoled-1.0.0/ -L-lconsoled ...`, or b) do it the dmd way: `dmd ~/.dub/packages/consoled-1.0.0/libconsoled.a ...`. b) works! :-) Many thanks!! a) doesn't work, I need to search for more information on linking as I would like to understand these kind of basics in D :-). The books I consulted so far (Learn D and D cookbook) did not help me to understand the linking so far ... I don't know what's going on there, but there shouldn't be a std/range.d with recent versions of phobos. It's a package since 2.067.0. Maybe a leftover from a previous installation? I just reinstalled it and it seems as it would have installed in the directory mentioned by ldc2: -- Installing: /usr/local/include/d/std/range -- Installing: /usr/local/include/d/std/range/primitives.d -- Installing: /usr/local/include/d/std/range/package.d -- Installing: /usr/local/include/d/std/range/interfaces.d But is there a file /usr/local/include/d/std/range.d? If so, that's apparently not from your latest install, and it may confuse ldc. If there is no such file, then I can't make any sense of the error messages. Oh yes there is such a file (and others). I need to clean these redundant files up ... Thanks here as well!
Re: Template this parameter in constructor
On 2/21/16 11:48 AM, Vlad Leberstein wrote: Hi! I'm struggling to use "Template This Parameters" feature(as described in https://dlang.org/spec/template.html#TemplateThisParameter) in class constructor. But it's usage isn't documented very clearly and I'm not even sure if it's supposed to work this way. Consider the following example: class C1 { this(this This)() { pragma(msg, "C1 constructor: "~__traits(identifier, This)); } } class C2 : C1 { this(this This)() { pragma(msg, "C2 constructor: "~__traits(identifier, This)); super(); } } class C3 : C2 { this(this This)() { pragma(msg, "C3 constructor: "~__traits(identifier, This)); super(); } } int main(string[] args) { auto test = new C3(); return 0; } The output is: C3 constructor: C3 C2 constructor: C3 C1 constructor: C2 As you can see this works but doesn't produce the desired behavior - we can't get static type of the C3 class in C1 constructor. I suspect that it's somehow related to the fact that templated functions can't be virtual. And here comes the question: Is this a bug or the way things are supposed to work(and hence should be documented)? This isn't a bug. Here is what happens. 1. template this is assigned the compile-time type of the object *when the function is called*. 2. A base class constructor is called from the next derived constructor. So C2's constructor is called from C3's, and C1's constructor is called from C2's. So it follows that the template this type will be the next derived constructor (or the type itself if that is the most derived type), because that's the compile-time type the object's ctor is called with. It would be immensely helpful to have such kind of compile-time information(for usecases vastly similar to what's described in http://forum.dlang.org/thread/mailman.1403.1361371073.22503.digitalmar...@puremagic.com) cause currently I'm using some kind of CRTP pattern with multilevel inheritance support instead and it feels very very very weird in D world. I think you may be able to do something like this: this(T = typeof(this))() { super!T(); } But I'm not sure if it works. -Steve
Re: compilation issues (dmd, rdmd, ldc2)
On Sunday, 21 February 2016 at 21:21:30 UTC, kraxli wrote: Thanks for coming back on that! The problem is the consoled-package which has the library: ~/.dub/packages/consoled-1.0.0/libconsoled.a So I link it (or aim to do it ;-) ) but dmd cannot find it: $ dmd -I~/.dub/packages/consoled-1.0.0/source -L-l~/.dub/packages/consoled-1.0.0/libconsoled appX.d /usr/bin/ld: cannot find -l~/.dub/packages/consoled-1.0.0/libconsoled collect2: error: ld returned 1 exit status --- errorlevel 1 I don't think it works like that. If I remember correctly, you can either a) do it the linker way: `dmd -L-L~/.dub/packages/consoled-1.0.0/ -L-lconsoled ...`, or b) do it the dmd way: `dmd ~/.dub/packages/consoled-1.0.0/libconsoled.a ...`. I don't know what's going on there, but there shouldn't be a std/range.d with recent versions of phobos. It's a package since 2.067.0. Maybe a leftover from a previous installation? I just reinstalled it and it seems as it would have installed in the directory mentioned by ldc2: -- Installing: /usr/local/include/d/std/range -- Installing: /usr/local/include/d/std/range/primitives.d -- Installing: /usr/local/include/d/std/range/package.d -- Installing: /usr/local/include/d/std/range/interfaces.d But is there a file /usr/local/include/d/std/range.d? If so, that's apparently not from your latest install, and it may confuse ldc. If there is no such file, then I can't make any sense of the error messages.
Re: compilation issues (dmd, rdmd, ldc2)
On Sunday, 21 February 2016 at 20:50:11 UTC, anonymous wrote: On Sunday, 21 February 2016 at 20:04:34 UTC, kraxli wrote: What is going on here and what is the difference between dmd and rdmd? dmd compiles the modules that you specify on the command line. By default, it then links an executable from the generated object files. The linking can only work when you give dmd all the code, either in source form or in compiled object form. When something is missing, you get "undefined reference" errors. Thanks for coming back on that! The problem is the consoled-package which has the library: ~/.dub/packages/consoled-1.0.0/libconsoled.a So I link it (or aim to do it ;-) ) but dmd cannot find it: $ dmd -I~/.dub/packages/consoled-1.0.0/source -L-l~/.dub/packages/consoled-1.0.0/libconsoled appX.d /usr/bin/ld: cannot find -l~/.dub/packages/consoled-1.0.0/libconsoled collect2: error: ld returned 1 exit status --- errorlevel 1 That means, when your program has multiple source files (including libraries), you must put them all on the dmd command line. Or you can compile modules individually (without linking, -c flag), and then put the generated object files on the command line when linking. rdmd is a wrapper around dmd (or another, compatible compiler). It reads the dependency tree of the modules, and runs dmd on all of the source files at once. That means, you only need to put the root module on the command line for rdmd. rdmd reads the imports and generates a full list of source files for dmd. Moreover, ldc2 has conflicts with modules which is probably due to installation, linking and scope issues. How can I shrink the scope for ldc2 such that it only looks at the "right place" for modules (and where is that?) ? $ ldc2 -I~/.dub/packages/consoled-1.0.0/source/ appX.d /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range I don't know what's going on there, but there shouldn't be a std/range.d with recent versions of phobos. It's a package since 2.067.0. Maybe a leftover from a previous installation? I just reinstalled it and it seems as it would have installed in the directory mentioned by ldc2: -- Installing: /usr/local/include/d/std/range -- Installing: /usr/local/include/d/std/range/primitives.d -- Installing: /usr/local/include/d/std/range/package.d -- Installing: /usr/local/include/d/std/range/interfaces.d
Re: compilation issues (dmd, rdmd, ldc2)
On Sunday, 21 February 2016 at 20:04:34 UTC, kraxli wrote: What is going on here and what is the difference between dmd and rdmd? dmd compiles the modules that you specify on the command line. By default, it then links an executable from the generated object files. The linking can only work when you give dmd all the code, either in source form or in compiled object form. When something is missing, you get "undefined reference" errors. That means, when your program has multiple source files (including libraries), you must put them all on the dmd command line. Or you can compile modules individually (without linking, -c flag), and then put the generated object files on the command line when linking. rdmd is a wrapper around dmd (or another, compatible compiler). It reads the dependency tree of the modules, and runs dmd on all of the source files at once. That means, you only need to put the root module on the command line for rdmd. rdmd reads the imports and generates a full list of source files for dmd. Moreover, ldc2 has conflicts with modules which is probably due to installation, linking and scope issues. How can I shrink the scope for ldc2 such that it only looks at the "right place" for modules (and where is that?) ? $ ldc2 -I~/.dub/packages/consoled-1.0.0/source/ appX.d /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range I don't know what's going on there, but there shouldn't be a std/range.d with recent versions of phobos. It's a package since 2.067.0. Maybe a leftover from a previous installation?
compilation issues (dmd, rdmd, ldc2)
I have problems with compiling a very simple program which loads a couple of modules/functions (which I would like to use later on). rdmd -I~/.dub/packages/consoled-1.0.0/source/ appX.d runs great :-) and also dub runs works. But dmd only returns: ´´´ $ dmd -I~/.dub/packages/consoled-1.0.0/source/ appX.d appX.o:(.rodata+0x98): undefined reference to `_D8consoled12__ModuleInfoZ' collect2: error: ld returned 1 exit status --- errorlevel 1 ´´´ What is going on here and what is the difference between dmd and rdmd? Moreover, ldc2 has conflicts with modules which is probably due to installation, linking and scope issues. How can I shrink the scope for ldc2 such that it only looks at the "right place" for modules (and where is that?) ? $ ldc2 -I~/.dub/packages/consoled-1.0.0/source/ appX.d /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range /usr/local/include/d/std/algorithm/iteration.d(59): Error: package name 'std.algorithm' conflicts with usage as a module name in file /usr/local/include/d/std/algorithm.d /usr/local/include/d/std/range.d(287): Error: module std.range from file /usr/local/include/d/std/range.d conflicts with package name range In case it is of any interest my dummy code is: ´´´ import std.stdio; import consoled; /* https://github.com/robik/ConsoleD */ import str = std.string; import curl = std.net.curl; import rx = std.regex; import std.algorithm.iteration : splitter, joiner; import std.algorithm : map; import std.typecons; import dt = std.datetime; import ar = std.array; import math = std.math : floor, ceil; import std.conv : to; import std.format : format; import std.array; import std.range.primitives; import json = std.json; import std.range : iota; void main(string[] args) { writeln("==\nNice it compiles and runs :-)\n=="); } ´´´ I am working on Ubuntu 14.04 (64bit), with dmd 2.070, rdmd build 20160127 and ldc2 (installed from source without any extra flags) is based on DMD v2.068.2 and LLVM 3.6.0.
Re: ldc application unable to start
On Sunday, 21 February 2016 at 17:54:30 UTC, Rainer Schuetze wrote: This error code is often caused by a DLL being compiled for the wrong architecture, so I guess that you have some 32-bit DLL in your original folder that is found instead of the 64-bit DLL. That pointed me in the direction of the problem. For some reason on the computer I'm using I had only added the 32bit dll to the system path. I added the 64bit, logged out and logged back in and it worked.
Re: ldc application unable to start
On 21.02.2016 18:11, jmh530 wrote: The application was unable to start correctly (0xc7b). Click OK to close the application. This error code is often caused by a DLL being compiled for the wrong architecture, so I guess that you have some 32-bit DLL in your original folder that is found instead of the 64-bit DLL.
Re: Get memory usage report from GC
On 20.02.2016 07:22, tcak wrote: On Saturday, 20 February 2016 at 05:55:26 UTC, Jon D wrote: On Saturday, 20 February 2016 at 05:34:01 UTC, tcak wrote: On Saturday, 20 February 2016 at 05:33:00 UTC, tcak wrote: Is there any way (I checked core.memory already) to collect report about memory usage from garbage collector? So, I can see a list of pointer and length information. Since getting this information would require another memory area in heap, it could be like logging when report is asked. My long running but idle program starts using 41.7% of memory (that's close to 3GB), and it is not obvious whether the memory is allocated by a single variable, or many variables. My mistake, it is close to 512MB. Doesn't sounds like precisely what you want, but there are summary reports of GC activity available via the "--DRT-gcopt=profile:1" command line option. More info at: http://dlang.org/spec/garbage.html --Jon I checked it out now. Yes, it is not that much useful unfortunately. The process is a daemon. stdin, stdout, and stderr are forwarded to /dev/null, thus, there is nothing like getting a text report at the end of process. I am still looking for a way to at least hook up to GC, so when it allocates, or deallocates, I could log it myself. You can add path-to-druntime/src/gc/gc.d to your build command line and add option -debug=PRINTF_TO_FILE. This will redirect output to gcx.log. If you add option -debug=PRINTF, it will print some API calls. You might have to check gc.d whether the ones that interest you are commented out, though.
ldc application unable to start
I'm playing around with ldc on Windows 64bit. I'm able to compile some simple stuff, but I'm having an issue with something I compile giving an error: The application was unable to start correctly (0xc7b). Click OK to close the application. This is effectively the ldc2 command I had run ldc2 -m64 .\example\example.d .\source\[folder]\[file3].d .\source\[folder]\[file3].d .\source\[folder]\[file3].d -L=.\lib\win64\[libname].lib (note that [libname].lib is a C library compiled with 64bit MSVC). I also got the same error with ldc2 -m64 .\example\example.d .\source\[folder]\[file3].d .\source\[folder]\[file3].d .\source\[folder]\[file3].d .\lib\win64\[libname].lib Because it compiles just fine with dmd, I figured there might be some issue with the way I'm doing the folder structure and passing that to ldc2. So I tried making a separate directory without the folder structure and ran ldc2 -m64 example.d [file1].d [file1].d [file1].d -L=[libname].lib and the program runs just fine. This suggests that I'm doing something wrong with how I refer to the files in the folder structure, but I have no idea what. I tried a few things, but it's probably something obvious I hadn't thought of.
Template this parameter in constructor
Hi! I'm struggling to use "Template This Parameters" feature(as described in https://dlang.org/spec/template.html#TemplateThisParameter) in class constructor. But it's usage isn't documented very clearly and I'm not even sure if it's supposed to work this way. Consider the following example: class C1 { this(this This)() { pragma(msg, "C1 constructor: "~__traits(identifier, This)); } } class C2 : C1 { this(this This)() { pragma(msg, "C2 constructor: "~__traits(identifier, This)); super(); } } class C3 : C2 { this(this This)() { pragma(msg, "C3 constructor: "~__traits(identifier, This)); super(); } } int main(string[] args) { auto test = new C3(); return 0; } The output is: C3 constructor: C3 C2 constructor: C3 C1 constructor: C2 As you can see this works but doesn't produce the desired behavior - we can't get static type of the C3 class in C1 constructor. I suspect that it's somehow related to the fact that templated functions can't be virtual. And here comes the question: Is this a bug or the way things are supposed to work(and hence should be documented)? It would be immensely helpful to have such kind of compile-time information(for usecases vastly similar to what's described in http://forum.dlang.org/thread/mailman.1403.1361371073.22503.digitalmar...@puremagic.com) cause currently I'm using some kind of CRTP pattern with multilevel inheritance support instead and it feels very very very weird in D world. Thanks in advance!
Re: Simple performance question from a newcomer
On Sunday, 21 February 2016 at 16:36:22 UTC, ZombineDev wrote: On Sunday, 21 February 2016 at 16:29:26 UTC, ZombineDev wrote: ... And if I use the Kahan algorithm: 106 ms 36 ms 31 ms The second two results are probably larger due to noise. I did some more testing and clearly the larger times for N=1000 were just noise: [LDC Kahan N=1000] 106 ms 36 ms 31 ms 59 ms 24 ms 22 ms ... Just for the record, with `DMD -release -O -inline`, Kahan, N=1000 I get: 325 ms 217 ms 165 ms 231 ms 117 ms 58 ms 131 ms 109 ms 58 ms 131 ms 109 ms 57 ms 131 ms 112 ms 57 ms 125 ms 106 ms 55 ms 125 ms 104 ms 55 ms 125 ms 105 ms 55 ms 125 ms 104 ms 55 ms 230 ms 115 ms 58 ms 131 ms 112 ms 58 ms 131 ms 109 ms 57 ms
Re: Simple performance question from a newcomer
On Sunday, 21 February 2016 at 16:29:26 UTC, ZombineDev wrote: ... And if I use the Kahan algorithm: 106 ms 36 ms 31 ms The second two results are probably larger due to noise. I did some more testing and clearly the larger times for N=1000 were just noise: [LDC Kahan N=1000] 106 ms 36 ms 31 ms 59 ms 24 ms 22 ms 46 ms 21 ms 20 ms 45 ms 21 ms 20 ms 45 ms 21 ms 20 ms 59 ms 24 ms 21 ms 102 ms 35 ms 30 ms 104 ms 37 ms 29 ms 107 ms 36 ms 31 ms 46 ms 21 ms 20 ms
Re: Simple performance question from a newcomer
On Sunday, 21 February 2016 at 14:32:15 UTC, dextorious wrote: I've been vaguely aware of D for many years, but the recent addition of std.experimental.ndslice finally inspired me to give it a try, since my main expertise lies in the domain of scientific computing and I primarily use Python/Julia/C++, where multidimensional arrays can be handled with a great deal of expressiveness and flexibility. Before writing anything serious, I wanted to get a sense for the kind of code I would have to write to get the best performance for numerical calculations, so I wrote a trivial summation benchmark. The following code gave me slightly surprising results: import std.stdio; import std.array : array; import std.algorithm; import std.datetime; import std.range; import std.experimental.ndslice; void main() { int N = 1000; int Q = 20; int times = 1_000; double[] res1 = uninitializedArray!(double[])(N); double[] res2 = uninitializedArray!(double[])(N); double[] res3 = uninitializedArray!(double[])(N); auto f = iota(0.0, 1.0, 1.0 / Q / N).sliced(N, Q); StopWatch sw; double t0, t1, t2; sw.start(); foreach (unused; 0..times) { for (int i=0; iauto sumtest3(Range)(Range f, double[] retval, double N, double Q) @safe pure nothrow @nogc { for (int i=0; iWhen I compiled it using dmd -release -inline -O -noboundscheck ../src/main.d, I got the following timings: 1268 ms 312 ms 271 ms I had heard while reading up on the language that in D explicit loops are generally frowned upon and not necessary for the usual performance reasons. Nevertheless, the two explicit loop functions gave me an improvement by a factor of 4+. Furthermore, the difference between sumtest2 and sumtest3 seems to indicate that function calls have a significant overhead. I also tried using f.reduce!((a, b) => a + b) instead of f.sum in sumtest1, but that yielded even worse performance. I did not try the GDC/LDC compilers yet, since they don't seem to be up to date on the standard library and don't include the ndslice package last I checked. Now, seeing as how my experience writing D is literally a few hours, is there anything I did blatantly wrong? Did I miss any optimizations? Most importantly, can the elegant operator chaining style be generally made as fast as the explicit loops we've all been writing for decades? The problem is not with ranges, but with the particualr algorithm used for summing. If you look at the docs (http://dlang.org/phobos-prerelease/std_algorithm_iteration.html#.sum) you'll see that if the range has random-access `sum` will use the pair-wise algorithm. About the second and third tests, the problem is with DMD which should not be used when measuring performance (but only for development, because it has fast compile-times). These are the results that I get with LDC: Pair-wise (sumtest1): 415 ms 21 ms 20 ms And if I use the Kahan algorithm: 106 ms 36 ms 31 ms The second two results are probably larger due to noise. And if I increase N to 100_000: Pair-wise (sumtest1): 29557 ms 2061 ms 1990 ms Kahan: 4566 ms 2067 ms 1990 ms According to `dub --verbose`, my command-line was roughly this: ldc2 -ofapp -release -O5 -singleobj -w source/app.d ../../../../.dub/packages/mir-0.10.1-alpha/source/mir/ndslice/internal.d ../../../../.dub/packages/mir-0.10.1-alpha/source/mir/ndslice/iteration.d ../../../../.dub/packages/mir-0.10.1-alpha/source/mir/ndslice/package.d ../../../../.dub/packages/mir-0.10.1-alpha/source/mir/ndslice/selection.d ../../../../.dub/packages/mir-0.10.1-alpha/source/mir/ndslice/slice.d
Re: Simple performance question from a newcomer
On Sunday, 21 February 2016 at 14:32:15 UTC, dextorious wrote: I had heard while reading up on the language that in D explicit loops are generally frowned upon and not necessary for the usual performance reasons. First, a minor point, the D community is usually pretty careful not to frown on a particular coding style (unlike some communities) so if you are comfortable writing loops and it gives you the fastest code, you should do so. On the performance issue, you can see this related post about performance with reduce: http://forum.dlang.org/post/mailman.4829.1434623275.7663.digitalmar...@puremagic.com This was Walter's response: http://forum.dlang.org/post/mlvb40$1tdf$1...@digitalmars.com And this shows that LDC flat out does a better job of optimization in this case: http://forum.dlang.org/post/mailman.4899.1434779705.7663.digitalmar...@puremagic.com
Re: Simple performance question from a newcomer
On Sunday, 21 February 2016 at 14:32:15 UTC, dextorious wrote: Now, seeing as how my experience writing D is literally a few hours, is there anything I did blatantly wrong? Did I miss any optimizations? Most importantly, can the elegant operator chaining style be generally made as fast as the explicit loops we've all been writing for decades? First off, you should really be using GDC or LDC if you want speed. On how to do that, see my blog post about here: http://jackstouffer.com/blog/nd_slice.html. Specifically the section titled "Getting Hands On". Secondly, both of your other sum examples use naive element by element summation rather than the more accurate pairwise summation which sum uses with random access floating point ranges. So your not really comparing apples to apples here. Since Phobos' pairwise summation is recursive, it's very likely that DMD isn't doing all the optimizations that LDC or GDC can, such as inlining or tail call optimizations. I haven't compiled your code so I can't check myself. Also, templates are auto attributed, so there's no reason to include @safe nothrow, etc. on templated functions.
Re: Simple performance question from a newcomer
So I guess pairwise summation is one to blame here. Dne 21.2.2016 v 16:56 Daniel Kozak napsal(a): You can use -profile to see what is causing it. Num TreeFuncPer CallsTimeTimeCall 2300 550799875 550243765 23 pure nothrow @nogc @safe double std.algorithm.iteration.sumPairwise!(double, std.experimental.ndslice.slice.Slice!(1uL, std.range.iota!(double, double, double).iota(double, double, double).Result).Slice).sumPairwise(std.experimental.ndslice.slice.Slice!(1uL, std.range.iota!(double, double, double).iota(double, double, double).Result).Slice) Dne 21.2.2016 v 15:32 dextorious via Digitalmars-d-learn napsal(a): I've been vaguely aware of D for many years, but the recent addition of std.experimental.ndslice finally inspired me to give it a try, since my main expertise lies in the domain of scientific computing and I primarily use Python/Julia/C++, where multidimensional arrays can be handled with a great deal of expressiveness and flexibility. Before writing anything serious, I wanted to get a sense for the kind of code I would have to write to get the best performance for numerical calculations, so I wrote a trivial summation benchmark. The following code gave me slightly surprising results: import std.stdio; import std.array : array; import std.algorithm; import std.datetime; import std.range; import std.experimental.ndslice; void main() { int N = 1000; int Q = 20; int times = 1_000; double[] res1 = uninitializedArray!(double[])(N); double[] res2 = uninitializedArray!(double[])(N); double[] res3 = uninitializedArray!(double[])(N); auto f = iota(0.0, 1.0, 1.0 / Q / N).sliced(N, Q); StopWatch sw; double t0, t1, t2; sw.start(); foreach (unused; 0..times) { for (int i=0; iauto sumtest3(Range)(Range f, double[] retval, double N, double Q) @safe pure nothrow @nogc { for (int i=0; iWhen I compiled it using dmd -release -inline -O -noboundscheck ../src/main.d, I got the following timings: 1268 ms 312 ms 271 ms I had heard while reading up on the language that in D explicit loops are generally frowned upon and not necessary for the usual performance reasons. Nevertheless, the two explicit loop functions gave me an improvement by a factor of 4+. Furthermore, the difference between sumtest2 and sumtest3 seems to indicate that function calls have a significant overhead. I also tried using f.reduce!((a, b) => a + b) instead of f.sum in sumtest1, but that yielded even worse performance. I did not try the GDC/LDC compilers yet, since they don't seem to be up to date on the standard library and don't include the ndslice package last I checked. Now, seeing as how my experience writing D is literally a few hours, is there anything I did blatantly wrong? Did I miss any optimizations? Most importantly, can the elegant operator chaining style be generally made as fast as the explicit loops we've all been writing for decades?
Re: Simple performance question from a newcomer
You can use -profile to see what is causing it. Num TreeFuncPer CallsTimeTimeCall 2300 550799875 550243765 23 pure nothrow @nogc @safe double std.algorithm.iteration.sumPairwise!(double, std.experimental.ndslice.slice.Slice!(1uL, std.range.iota!(double, double, double).iota(double, double, double).Result).Slice).sumPairwise(std.experimental.ndslice.slice.Slice!(1uL, std.range.iota!(double, double, double).iota(double, double, double).Result).Slice) Dne 21.2.2016 v 15:32 dextorious via Digitalmars-d-learn napsal(a): I've been vaguely aware of D for many years, but the recent addition of std.experimental.ndslice finally inspired me to give it a try, since my main expertise lies in the domain of scientific computing and I primarily use Python/Julia/C++, where multidimensional arrays can be handled with a great deal of expressiveness and flexibility. Before writing anything serious, I wanted to get a sense for the kind of code I would have to write to get the best performance for numerical calculations, so I wrote a trivial summation benchmark. The following code gave me slightly surprising results: import std.stdio; import std.array : array; import std.algorithm; import std.datetime; import std.range; import std.experimental.ndslice; void main() { int N = 1000; int Q = 20; int times = 1_000; double[] res1 = uninitializedArray!(double[])(N); double[] res2 = uninitializedArray!(double[])(N); double[] res3 = uninitializedArray!(double[])(N); auto f = iota(0.0, 1.0, 1.0 / Q / N).sliced(N, Q); StopWatch sw; double t0, t1, t2; sw.start(); foreach (unused; 0..times) { for (int i=0; iauto sumtest3(Range)(Range f, double[] retval, double N, double Q) @safe pure nothrow @nogc { for (int i=0; iWhen I compiled it using dmd -release -inline -O -noboundscheck ../src/main.d, I got the following timings: 1268 ms 312 ms 271 ms I had heard while reading up on the language that in D explicit loops are generally frowned upon and not necessary for the usual performance reasons. Nevertheless, the two explicit loop functions gave me an improvement by a factor of 4+. Furthermore, the difference between sumtest2 and sumtest3 seems to indicate that function calls have a significant overhead. I also tried using f.reduce!((a, b) => a + b) instead of f.sum in sumtest1, but that yielded even worse performance. I did not try the GDC/LDC compilers yet, since they don't seem to be up to date on the standard library and don't include the ndslice package last I checked. Now, seeing as how my experience writing D is literally a few hours, is there anything I did blatantly wrong? Did I miss any optimizations? Most importantly, can the elegant operator chaining style be generally made as fast as the explicit loops we've all been writing for decades?
Re: 111
On Sunday, 21 February 2016 at 14:03:56 UTC, Ivan Kazmenko wrote: On Sunday, 21 February 2016 at 12:35:31 UTC, Lisa wrote: ... Is there smth wrong again? Yes. As a programmer, most of the time, you will have to try your programs by yourself before you consider them correct. Now, run a compiler, and it complains: - main.d(20): Error: cannot return non-void from void function - Line 20 of your program is "return 0;", and the void function in question is "void main() {...}". So, you have to fix either of that: make main return int instead of void, or remove the return line. After that, the program will finally compile. But that's not the end, you have to try running it. "Enter side A:" shall we say, "1" and then it writes "Enter side B:" and fails: - std.conv.ConvException@c:\Tools\dmd\windows\bin\..\..\src\phobos\std\conv.d(2729): no digits seen 0x0040666A in ... - That's a whole lot of unfriendly error text on the screen, but the human-readable part is "no digits seen" when reading variable B. Now, read the chapter of Ali's book again very carefully, or one of the posts here. You may then notice that the space inside the quotes is important, and also learn why. The bottom line: the task of writing a program is not finished until you can compile it, run it, give it at least a few example inputs, and it prints the right output for all these inputs. Ivan Kazmenko. Thank you so much! :) Thanks everyone!) You're really cool)
Re: vk.xml
On Sunday, 21 February 2016 at 12:52:33 UTC, Nicholas Wilson wrote: So I was going through the vulcan spec to try to create a better D bindings for it. (pointer /len pairs to arrays adhering to D naming conventions and prettying up the *Create functions functions like vkResult *Create( arg ,&arg, retptr) to a fancy throw on misuse struct with constructors and that kind of stuff.) the structure of the registry is as follows. struct KHR_registry { } I'm glad to see more people looking to create a D binding from vk.xml! I was also working on this (http://forum.dlang.org/post/ygylvtuwwiwyqtcnl...@forum.dlang.org), unfortunately I won't be able to continue my work until early March, so I hope you'll do a good job in the mean time ;) Unfortunately the spec is written in a very C specific way so we need to have a bunch of special cases for parsing the C code that's interleaved with the XML tags. I haven't used std.xml yet, but I hope I may be able to help you. where "string content" is the string between the tags (does this have a name?) and thing with @Tag are always in the tag (although it is also inconsistent). I tried looking at the docs for std.xml but they were not very helpful. May be you can use http://dlang.org/phobos/std_xml#.Element.text in combination with http://dlang.org/phobos/std_xml#.Element.elements To further complicate things not all of the fields are present in all cases also I need to keep track of the number of '*' (see fields named indirections) after a tag has closed for pointer type declarations in function signatures and structs. You mean things like: void** ppData (from the vkMapMemory command) ? Yeah this is extremely ugly. One way to do it is to go to the "param" XML element and check if the size of it's elements matches it's text size. In the case above everything between and is 39 characters and the two tags are 17 and 19 character respectively (total 36) which leaves 3 chars for the indirections. If we make a pass to remove all whitespace between tags (between ">" and "<") we should get exactly 2 characters which is the number of indirection we're looking for. Another way is to just strip the tags and leave only their internal text. In the above example the result should be: void** ppData which is valid D code and we can leave it that way for now. Also is there a way to do sane cross referencing without having internal pointers everywhere. I am no XML expert (so there may be an easier way), but I think it would be easier if we use associative arrays, instead of plain arrays. That way we can check for example: if ("VkBuffer" in types && "VkDevice" in types) types["VkBuffer"].parent = types["VkDevice"]; I'm sure there should be a very elegant way to do this by recursing down through the sub-structs The simplest solution, IMO, is to insert all the types, commands, enums, etc. in associative arrays first and then do cross-referencing. E.g. Type[string] types; struct Type { // ... other members // Set to string first, and later change // to the proper Type, after the whole `types` table has been read. Algebraic(string, Type*) parent; // ... more members } Otherwise the only sane way to do forward reference resolution is to use D Fibers. I have used fibers in some of my projects, but the extra complications are not worth it for this task as the xml is only 5100 lines and the performance benefits probably would not be very large. Many thanks Nic BTW if you run into some other issues with std.xml, you can also check http://arsdnet.net/web.d/dom.html and https://github.com/burner/std.xml2 Also don't forget to use unittests extensively!
Re: Simple performance question from a newcomer
On Sunday, 21 February 2016 at 14:32:15 UTC, dextorious wrote: Now, seeing as how my experience writing D is literally a few hours, is there anything I did blatantly wrong? Did I miss any optimizations? Most importantly, can the elegant operator chaining style be generally made as fast as the explicit loops we've all been writing for decades? I didn't look at your code that thoroughly, but it is generally recommended that if you're concerned about performance to compile with gdc or ldc. dmd has fast compile times, but does not produce as fast of code. You might want to check if the performance differential is still large with one of those.
Simple performance question from a newcomer
I've been vaguely aware of D for many years, but the recent addition of std.experimental.ndslice finally inspired me to give it a try, since my main expertise lies in the domain of scientific computing and I primarily use Python/Julia/C++, where multidimensional arrays can be handled with a great deal of expressiveness and flexibility. Before writing anything serious, I wanted to get a sense for the kind of code I would have to write to get the best performance for numerical calculations, so I wrote a trivial summation benchmark. The following code gave me slightly surprising results: import std.stdio; import std.array : array; import std.algorithm; import std.datetime; import std.range; import std.experimental.ndslice; void main() { int N = 1000; int Q = 20; int times = 1_000; double[] res1 = uninitializedArray!(double[])(N); double[] res2 = uninitializedArray!(double[])(N); double[] res3 = uninitializedArray!(double[])(N); auto f = iota(0.0, 1.0, 1.0 / Q / N).sliced(N, Q); StopWatch sw; double t0, t1, t2; sw.start(); foreach (unused; 0..times) { for (int i=0; iauto sumtest3(Range)(Range f, double[] retval, double N, double Q) @safe pure nothrow @nogc { for (int i=0; iWhen I compiled it using dmd -release -inline -O -noboundscheck ../src/main.d, I got the following timings: 1268 ms 312 ms 271 ms I had heard while reading up on the language that in D explicit loops are generally frowned upon and not necessary for the usual performance reasons. Nevertheless, the two explicit loop functions gave me an improvement by a factor of 4+. Furthermore, the difference between sumtest2 and sumtest3 seems to indicate that function calls have a significant overhead. I also tried using f.reduce!((a, b) => a + b) instead of f.sum in sumtest1, but that yielded even worse performance. I did not try the GDC/LDC compilers yet, since they don't seem to be up to date on the standard library and don't include the ndslice package last I checked. Now, seeing as how my experience writing D is literally a few hours, is there anything I did blatantly wrong? Did I miss any optimizations? Most importantly, can the elegant operator chaining style be generally made as fast as the explicit loops we've all been writing for decades?
Re: 111
On Sunday, 21 February 2016 at 12:35:31 UTC, Lisa wrote: ... Is there smth wrong again? Yes. As a programmer, most of the time, you will have to try your programs by yourself before you consider them correct. Now, run a compiler, and it complains: - main.d(20): Error: cannot return non-void from void function - Line 20 of your program is "return 0;", and the void function in question is "void main() {...}". So, you have to fix either of that: make main return int instead of void, or remove the return line. After that, the program will finally compile. But that's not the end, you have to try running it. "Enter side A:" shall we say, "1" and then it writes "Enter side B:" and fails: - std.conv.ConvException@c:\Tools\dmd\windows\bin\..\..\src\phobos\std\conv.d(2729): no digits seen 0x0040666A in ... - That's a whole lot of unfriendly error text on the screen, but the human-readable part is "no digits seen" when reading variable B. Now, read the chapter of Ali's book again very carefully, or one of the posts here. You may then notice that the space inside the quotes is important, and also learn why. The bottom line: the task of writing a program is not finished until you can compile it, run it, give it at least a few example inputs, and it prints the right output for all these inputs. Ivan Kazmenko.
vk.xml
So I was going through the vulcan spec to try to create a better D bindings for it. (pointer /len pairs to arrays adhering to D naming conventions and prettying up the *Create functions functions like vkResult *Create( arg ,&arg, retptr) to a fancy throw on misuse struct with constructors and that kind of stuff.) the structure of the registry is as follows. struct KHR_registry { string comment; // Not as xml comment but a ... struct vendorid { string @Tag name; string @Tag id; string @Tag comment; } vendorid[] vendorids; struct tag { string @Tag name; string @Tag author; string @Tag contact; } tag[] tags; struct validity_type// does not appear at this level but is common to commands and types { struct usage_type { string content; } usage_type[] usage; } struct type { string name;// inconsistanly in tag and content string requires; string parent; string content; enum category_tpye { include, define, basetype, bitmask, handle, enum_, funcpointer, struct_, } category_tpye category; bool returnedonly; validity_type validity; struct member { string typename; //name of the members type variable tag type string name;//name of the member variable string len;//companion member length variable for array pointers bool optional; //should generate as a default value bool noautovalidity; } enums* enum;//pointer to corresponding type enum definition struct params { type* paramType;//for some reason any pointer qualifiactions occur after e.g. // void * see coment below string name; size_t inderections; // number of pointer inderections before reaching the type pointed to // by paramType // functions taking no args will have parameters == [] string content; } params[] parameters; } type[] types; struct enums { string name,comment, type, expand; // expand is the C enum's Prefix e.g. VK_QUERY_TYPE struct enum_ { string value, name, comment; } } struct command { string successcodes; string errorcodes; string content; struct proto_type { string content; type* returnType; string name; } proto_type proto; struct pram { string content; bool optional; string externsync; string len; size_t inderections; immutable invalidLen = "null-terminated"; // if len is this then it is not an array // although this is inconsistant. sometimes as a len // others in the validity } validity_type validity; string queues, renderpass, cmdbufferlevel; } command[] commands; struct feature { string api, name, number; /* */ struct require { string comment; string metaType; // type enum command see above variable tag type string name; } require[] requires; } struct extension { string name, number, supported; struct require { struct elem { string name, content; string metaType; //variable tag type string offset, extends; } } } extension[] extensions; } where "string content" is the string between the tags (does this have a name?) and thing with @Tag are always in the tag (although it is also inconsistent). I tried looking at the docs for std.xml but they were not very helpful. To further complicate things not all of the fields are present in all cases also I need to keep track of the number of '*' (see fields named indirections) after a tag has closed for pointer type declarations in function signatures and structs. Also is there a way to do sane cross referencing without having internal pointers everywhere. I'm sure there should be a very elegant way to do this by recursing down through the sub-structs Many thanks Nic
Re: 111
On Saturday, 20 February 2016 at 12:59:58 UTC, Ivan Kazmenko wrote: On Saturday, 20 February 2016 at 04:15:50 UTC, Lisa wrote: module main; import std.stdio; import std.math; int main() { int A, B, C; writef("A = "); readf("%lf", %A); writef("B = "); readf("%lf", %B); writef("C1= "); readf("%lf", %C); writefl("P = (%lf)", A + B + C); return 0; } It whatever doesn't work The line "int A, B, C;" should be "double A, B, C;" if you want to be able to operate non-integer lengths as well. The lines like "readf("%lf", %A);" should be "readf(" %s", &A);". Please read the reasoning again carefully in Ali's book: http://ddili.org/ders/d.en/input.html. The " %s" can be " %f" but not " %lf" (that would be the correct string for C's printf but not for D's readf), and the leading space is important. On the output line, you perhaps meant "writefln" instead of "writefl". Again, "%lf" should be changed into "%f" or "%s". import std.stdio; import std.math; void main() { writef("Enter side A: "); double A; readf("%s", &A); writef("Enter side B: "); double B; readf("%s", &B); writef("Enter side C: "); double C; readf("%s", &C); writefln("Perimetr is", A + B + C, " centimetrs."); return 0; } Is there smth wrong again?
Re: Status icon on Linux
On 02/20/2016 06:32 PM, Gerald wrote: On Saturday, 20 February 2016 at 11:36:11 UTC, Mike Wey wrote: The documentation states we should use notifications, that means i'll probably need to add libnotify bindings to GtkD. Though sending notifications using DBus is also possible. (https://developer.gnome.org/notification-spec/) Depending on the use case using notifications might or might not be useful. Would the support for libnotify be for those applications not using gtk.Application since it already supports sending notifications via sendNotification. I'm using it in Terminix and it works quite well. A search of the GTK documentation only gave me results form libnotify so i missed the GApplication / GNotification functionality. -- Mike Wey
Re: immutable class can't override opEquals, workaround?
On Sunday, February 21, 2016 04:25:59 SimonN via Digitalmars-d-learn wrote: > Hi, > > immutable class A { > int i; > this(int arg) { i = arg; } > override bool opEquals(Object rhsObj) > { > auto rhs = cast (immutable(A)) rhsObj; > return rhs && i == rhs.i; > } > } > > Error by dmd 2.070: > > ./immutclass.d(4): Error: function immutclass.A.opEquals > does not override any function, did you mean to override > 'object.Object.opEquals'? > > My understandings: > > 1. immutable class A means: All methods have immutable tacked > on them implicitly. > 2. Object.opEquals doesn't have immutable tacked on it. If I > want to override Object.opEquals, I should override without > 'immutable'. > 3. Overriding opEquals and toHash are necessary to make A > behave properly as AA key type. This is incompatible with > (2) in an immutable class. > 4. I found this thread: > How to turn an inout(Object) into a string > > http://forum.dlang.org/thread/dcobmtogyrmnaqnqy...@forum.dlang.org > that I interpret as: The need for the currently-impossible > override is acknowledged, but the implementation would bring > significant changes to the language, therefore the solution > is postponed. The above thread was from mid-2015, but I guess > it's still relevant. > > My workaround is: Make class _A private, and declare every method > immutable, except for what Object decrees to be mutable/const/... > Then make a public alias A = immutable(_A). > > Is there something better than this? > > Has there been any new development on Object method removal? > Jonathan M Davis has been pushing this hard 2 years ago, I'd > love to see the efforts make it into the language. :-) Okay. Until opEquals, toHash, toString, and opCmp have been removed from Object, you can't override any of them as anything other than mutable. opEquals still works with const and immutable objects via a hack in druntime (it casts away const inside of the free function opEquals which works if your opEquals behaves but results in undefined behavior if it mutates anything). So, I expect that it's simply not possible right now to use a class as a key in an AA, though a struct should work if it's defined appropriately. Certainly, if it's legal to use a class as the key in an AA, it's a bug given that there's no guarantee that it's immutable like a key needs to be. As for actually getting rid of opEquals and friends from Object, no real progress has been made. I finally have a working version of the PR to templatize the free function opEquals such that it will work with opEquals that take a derived class instead of Object (previously, compiler bugs kept getting in the way of it working), but it hasn't even been looked at yet from what I can tell, and it's the simplest of the bits that need to be done (https://github.com/D-Programming-Language/druntime/pull/1439). The overhaul of the AA implementation to templatize it needs to be completed (and I'm not sure where it currently stands) and there will likely have to be some clever compiler changes to make it so that we can remove those 4 functions from Object without breaking code in the process. So, it's going to take a variety of people to get it done, and unfortunately, it hasn't been high on much of anyone's todo list. - Jonathan M Davis