Re: Private imports and Objects
On Thursday, November 30, 2017 06:29:43 helxi via Digitalmars-d-learn wrote: > 1. Why are imports visible from outside the package when you do > selective imports? > > //mod.d > module mod; > > import std.stdio : writeln; > > public void greet() > { > writeln("Hello"); > } > > > //app.d > import mod; > > void main() > { > mod.greet(); > writeln("You should not be seeing this."); > > } > > Compiles just fine and prints "You should not be seeing this." > just fine with `$dub build`. Even if I use package imports the > result stays the same. If you use a version of dmd that's at least semi-recent, you should see a deprecation message. It works due to a long standing bug that has been fixed, but when it was fixed, a number of aspects of imports were overhauled, and it was decided to phase in the new behavior to minimize code breakage, and as such, it should be printing a deprecation message at the moment, whereas in the future, it will become an error like it should be. > 2. Classes that do not inherit (base classes) actually inherit > from 'Object`. For which, often times one converts the Object to > its subclasses. What's the rationale behind this? > Isn't this going to add overhead? I don't understand the question. You're asking whether casting from a base class to a derived class creates overhead? Or are you asking whether having a base class for all classes creates overhead? Or something else? Object exists primarily because D didn't originally have templates, and when you don't have templates, having a single base class is the only way to have a function accept any class, and for something like a container, you'd pretty much be forced to use void* without Object if you don't have templates. However, once templates were added to D, the benefits of Object were significantly reduced, and it's arguably not a particularly good idea to be writing code that operates on Object. However, it's far too late in the game to get rid of Object. At one point, it was decided to remove Object's member functions, because having them on Object needlessly locks in a particular set of attributes for those functions, and if we did that, then there really wouldn't be much reason to use Object directly, but that change has never happened, and it's not clear that it's going to happen, since there are a number of technical issues that make it a bit of a pain to do (particularly if we don't want to break a lot of code). One of the bigger issues is that the AA implementation in druntime needs to be templated so that it doesn't need to operate on Object, and that's proven to be a bit of a challenge. https://issues.dlang.org/show_bug.cgi?id=9769 https://issues.dlang.org/show_bug.cgi?id=9770 https://issues.dlang.org/show_bug.cgi?id=9771 https://issues.dlang.org/show_bug.cgi?id=9772 - Jonathan M Davis
Re: std.range.interfaces : InputRange moveFront
On 11/29/2017 08:31 PM, Tony wrote: What does the moveFront() method do in the InputRange interface? std.range.interfaces : InputRange.moveFront() move is an operation that transfers the state of the source to the destination. The front element becomes its .init value and its previous values is returned by moveFront(). The important bit is that, the element is *not* copied: import std.range; struct S { int i; bool is_a_copy = false; this(this) { is_a_copy = true; } } void main() { auto r = [S(1)]; auto a = r.front; assert(a.is_a_copy); // yes, a is a copy assert(a.i == 1); // as expected, 1 assert(r.front.i == 1);// front is still 1 auto b = r.moveFront(); assert(!b.is_a_copy); // no, b is not a copy assert(b.i == 1); // state is transferred assert(r.front.i == 0);// front is int.init } Ali
Private imports and Objects
1. Why are imports visible from outside the package when you do selective imports? //mod.d module mod; import std.stdio : writeln; public void greet() { writeln("Hello"); } //app.d import mod; void main() { mod.greet(); writeln("You should not be seeing this."); } Compiles just fine and prints "You should not be seeing this." just fine with `$dub build`. Even if I use package imports the result stays the same. 2. Classes that do not inherit (base classes) actually inherit from 'Object`. For which, often times one converts the Object to its subclasses. What's the rationale behind this? Isn't this going to add overhead?
std.range.interfaces : InputRange moveFront
What does the moveFront() method do in the InputRange interface? std.range.interfaces : InputRange.moveFront()
Re: Changing the class data underneath some reference
On 11/29/17 10:22 PM, Jonathan M Davis wrote: With classes, you could also assign the entire state of the object similar to what you'd get with structs and opAssign, but you'd have to write a member function to do it. There's no reason that you couldn't do the equivalent of opAssign. It's just that there's no built-in operator for it. So, whatever member function you wrote for it would be non-standard. It's mostly a bad idea. The whole point of disallowing assignment is to prevent the slicing problem. It's also why opAssign isn't overloadable for classes assigning to classes in the same hierarchy. -Steve
Re: Andrei's "The D Programming Language" book. Up to date?
On Wednesday, November 29, 2017 17:26:11 Nick Treleaven via Digitalmars-d- learn wrote: > On Wednesday, 4 October 2017 at 20:49:26 UTC, John Gabriele wrote: > > What's changed in the language, library, and community since > > then that I should be aware of if following along with and > > learning from that book? > > Here's a list of significant things - maybe incomplete: > https://wiki.dlang.org/Differences_With_TDPL I didn't even realize that that page existed. I just made some tweaks to it, though it's still probably far from complete as far as stuff not mentioned in TDPL goes. As for unimplemented stuff, it made it sound like shared isn't implemented (which isn't true at all; it just doesn't have memory barriers like TDPL talks about; the big thing missing for shared is arguably that the memory model for D needs to be properly defined like C++ finally did, but TDPL doesn't talk about that at all), and the wiki page didn't list synchronized classes, which is the other big one that isn't implemented (though putting synchronized on classes actually has _some_ effect now, which it didn't until fairly recently). - Jonathan M Davis
Re: Changing the class data underneath some reference
On Wednesday, November 29, 2017 21:12:58 Steven Schveighoffer via Digitalmars-d-learn wrote: > On 11/29/17 7:40 PM, David Colson wrote: > > Hello all! > > > > I'm getting settled into D and I came into a problem. A code sample > > shows it best: > > > > class SomeType > > { > > > > string text; > > this(string input) {text = input;} > > > > } > > > > > > void main() > > { > > > > SomeType foo = new SomeType("Hello"); > > > > SomeType bar = foo; > > > > foo = new SomeType("World"); > > > > writeln(bar.text); // Prints hello > > // I'd like it to print World > > > > } > > > > In the C++ world I could do this using pointers and changing the data > > underneath a given pointer, but I can't use pointers in D, so I'm not > > sure how I can get this behaviour? > > > > I'd be open to other ways of achieving the same affect in D, using more > > D like methods. > > D does not support reassigning class data using assignment operator, > only the class reference. You can change the fields individually if you > need to. > > e.g.: > > foo.text = "World"; > > structs are value types in D and will behave similar to C++ > classes/structs. With classes, you could also assign the entire state of the object similar to what you'd get with structs and opAssign, but you'd have to write a member function to do it. There's no reason that you couldn't do the equivalent of opAssign. It's just that there's no built-in operator for it. So, whatever member function you wrote for it would be non-standard. Heck, technically, we don't even have a standard way to clone a class object like C# or Java do. Some folks write a clone function and others write a dup function; either way, there's nothing built-in or standard for it. - Jonathan M Davis
Re: Changing the class data underneath some reference
On Thursday, 30 November 2017 at 00:40:51 UTC, David Colson wrote: Hello all! I'm getting settled into D and I came into a problem. A code sample shows it best: class SomeType { string text; this(string input) {text = input;} } void main() { SomeType foo = new SomeType("Hello"); SomeType bar = foo; foo = new SomeType("World"); writeln(bar.text); // Prints hello // I'd like it to print World } In the C++ world I could do this using pointers and changing the data underneath a given pointer, but I can't use pointers in D, so I'm not sure how I can get this behaviour? I'd be open to other ways of achieving the same affect in D, using more D like methods. You are dealing with a reference type. Reference types can be though of as a value type of an address. The new operator can be though of as giving the variable a new address. This means the foo and bar variables are not bound to the same value because their referencing different address. You need a struct. Which isn't a reference.
Re: Changing the class data underneath some reference
On 11/29/17 7:40 PM, David Colson wrote: Hello all! I'm getting settled into D and I came into a problem. A code sample shows it best: class SomeType { string text; this(string input) {text = input;} } void main() { SomeType foo = new SomeType("Hello"); SomeType bar = foo; foo = new SomeType("World"); writeln(bar.text); // Prints hello // I'd like it to print World } In the C++ world I could do this using pointers and changing the data underneath a given pointer, but I can't use pointers in D, so I'm not sure how I can get this behaviour? I'd be open to other ways of achieving the same affect in D, using more D like methods. D does not support reassigning class data using assignment operator, only the class reference. You can change the fields individually if you need to. e.g.: foo.text = "World"; structs are value types in D and will behave similar to C++ classes/structs. -Steve
Re: Floating point types default to NaN?
On Friday, 24 November 2017 at 14:30:44 UTC, A Guy With a Question wrote: I would have expected 0 to be the default value. What's the logic behind having them being NaN by default? https://dlang.org/spec/type.html http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723
Re: Changing the class data underneath some reference
On Thursday, 30 November 2017 at 00:52:25 UTC, codephantom wrote: ... sorry, don't know how the int * got in there ;-) Anyway..who said you can't use pointers in D? Just change: //SomeType bar = foo; SomeType * bar =
Re: Changing the class data underneath some reference
On Thursday, 30 November 2017 at 00:40:51 UTC, David Colson wrote: Hello all! I'm getting settled into D and I came into a problem. A code sample shows it best: class SomeType { string text; this(string input) {text = input;} } void main() { SomeType foo = new SomeType("Hello"); SomeType bar = foo; foo = new SomeType("World"); writeln(bar.text); // Prints hello // I'd like it to print World } In the C++ world I could do this using pointers and changing the data underneath a given pointer, but I can't use pointers in D, so I'm not sure how I can get this behaviour? I'd be open to other ways of achieving the same affect in D, using more D like methods. void main() { SomeType foo = new SomeType("Hello"); int * ptr; SomeType * bar; bar = foo = new SomeType("World"); writeln(bar.text); // Prints World }
Re: Changing the class data underneath some reference
On Thursday, 30 November 2017 at 00:40:51 UTC, David Colson wrote: Hello all! I'm getting settled into D and I came into a problem. A code sample shows it best: class SomeType { string text; this(string input) {text = input;} } void main() { SomeType foo = new SomeType("Hello"); SomeType bar = foo; foo = new SomeType("World"); writeln(bar.text); // Prints hello // I'd like it to print World } In the C++ world I could do this using pointers and changing the data underneath a given pointer, but I can't use pointers in D, so I'm not sure how I can get this behaviour? I'd be open to other ways of achieving the same affect in D, using more D like methods. I made an example demonstrating what I'd do in C++: class SomeType { public: std::string text; SomeType(std::string input) {text = input;} }; int main() { SomeType foo = SomeType("Hello"); SomeType* bar = foo = SomeType("World"); std::cout << bar->text << "\n"; // Prints World }
Changing the class data underneath some reference
Hello all! I'm getting settled into D and I came into a problem. A code sample shows it best: class SomeType { string text; this(string input) {text = input;} } void main() { SomeType foo = new SomeType("Hello"); SomeType bar = foo; foo = new SomeType("World"); writeln(bar.text); // Prints hello // I'd like it to print World } In the C++ world I could do this using pointers and changing the data underneath a given pointer, but I can't use pointers in D, so I'm not sure how I can get this behaviour? I'd be open to other ways of achieving the same affect in D, using more D like methods.
Re: Basic questions about D lang?
On Tuesday, 28 November 2017 at 13:39:11 UTC, Jayam wrote: Can we compile our program to multi program ? Based on your C# reference you must be referring to the "Mixed Platform" build option. No, that is a .NET thing and D is not on .NET (that project has died). D requires a more traditional approach to multiple platforms, you'll need to write your code with the needs of your supported platforms in mind. Luckily in pure D this is like no work, but when you interface to C/C++ libraries you'll hit sizes of types and structures changing almost randomly (ok it isn't that bad).
Re: Andrei's "The D Programming Language" book. Up to date?
On Wednesday, 29 November 2017 at 17:26:11 UTC, Nick Treleaven wrote: On Wednesday, 4 October 2017 at 20:49:26 UTC, John Gabriele wrote: What's changed in the language, library, and community since then that I should be aware of if following along with and learning from that book? Here's a list of significant things - maybe incomplete: https://wiki.dlang.org/Differences_With_TDPL Nice! Thanks, Nick!
Re: Andrei's "The D Programming Language" book. Up to date?
On Wednesday, 29 November 2017 at 17:50:59 UTC, Arun Chandrasekaran wrote: Multiple alias this You can only have one subtyping member currently. Shared Not all of shared's guarantees are implemented yet. SafeD @safe (and therefore SafeD) isn't fully implemented. So, it doesn't necessarily work quite like it's supposed to yet. How much of these are relevant today with 2.077.0? The first two are true AIUI. @safe is mostly implemented, there's been a lot of progress on that since TDPL.
Re: Andrei's "The D Programming Language" book. Up to date?
On Wednesday, 29 November 2017 at 17:26:11 UTC, Nick Treleaven wrote: Here's a list of significant things - maybe incomplete: https://wiki.dlang.org/Differences_With_TDPL Multiple alias this You can only have one subtyping member currently. Shared Not all of shared's guarantees are implemented yet. SafeD @safe (and therefore SafeD) isn't fully implemented. So, it doesn't necessarily work quite like it's supposed to yet. How much of these are relevant today with 2.077.0?
Re: Andrei's "The D Programming Language" book. Up to date?
On Wednesday, 4 October 2017 at 20:49:26 UTC, John Gabriele wrote: What's changed in the language, library, and community since then that I should be aware of if following along with and learning from that book? Here's a list of significant things - maybe incomplete: https://wiki.dlang.org/Differences_With_TDPL
Re: Shared and race conditions
On Wednesday, 29 November 2017 at 17:03:42 UTC, Steven Schveighoffer wrote: On 11/29/17 11:13 AM, Wanderer wrote: I'm trying to simulate a race condition in D with the following code: (https://run.dlang.io/is/RfOX0I) One word of caution, I think the running of your code on run.dlang.io is cached. Refreshing doesn't make it re-run. https://run.dlang.io/is/k0LhQA -Steve Ah good catch.
Re: Shared and race conditions
On Wednesday, 29 November 2017 at 17:03:42 UTC, Steven Schveighoffer wrote: On 11/29/17 11:13 AM, Wanderer wrote: I'm trying to simulate a race condition in D with the following code: (https://run.dlang.io/is/RfOX0I) One word of caution, I think the running of your code on run.dlang.io is cached. Refreshing doesn't make it re-run. https://run.dlang.io/is/k0LhQA -Steve I was using this just for the reference, as I've noticed caching as well. Thanks Steve, for spending time and actually hitting a race!
Re: Shared and race conditions
On 11/29/17 11:13 AM, Wanderer wrote: I'm trying to simulate a race condition in D with the following code: (https://run.dlang.io/is/RfOX0I) One word of caution, I think the running of your code on run.dlang.io is cached. Refreshing doesn't make it re-run. https://run.dlang.io/is/k0LhQA -Steve
Re: Shared and race conditions
On 11/29/17 11:51 AM, Michael wrote: On Wednesday, 29 November 2017 at 16:33:50 UTC, Steven Schveighoffer wrote: On 11/29/17 11:13 AM, Wanderer wrote: [...] [snip] [...] Using the compiler switch -vcg-ast, I see no synchronization of these methods. [...] Any idea what has changed in DMD-nightly to retain the correct ordering of IDs? No idea. Perhaps it was another factor, as machine busyness could affect the ordering. The ordering of when the ids are fetched is pretty much the same (as long as no race has happened). It's really the printing of the ids that might be affected. -Steve
Re: Shared and race conditions
On 11/29/17 11:46 AM, Wanderer wrote: On Wednesday, 29 November 2017 at 16:33:50 UTC, Steven Schveighoffer wrote: On 11/29/17 11:13 AM, Wanderer wrote: [...] [snip] [...] Using the compiler switch -vcg-ast, I see no synchronization of these methods. [...] That's what I assume, I was just lucky not to see a race. Thanks for `-vcg-ast` switch! Really helpful, and it answered my questions as no syncronization code was added. FYI, I ran this about 15 times, finally got one: Stevens-MacBook-Pro:testd steves$ ./testshared next: MyId(1) next: MyId(2) next: MyId(3) next: MyId(4) next: MyId(5) next: MyId(6) next: MyId(7) next: MyId(8) next: MyId(9) next: MyId(10) next: MyId(11) next: MyId(12) next: MyId(12) <=== race next: MyId(13) next: MyId(14) next: MyId(15) next: MyId(16) next: MyId(17) next: MyId(18) next: MyId(19) next: MyId(20) next: MyId(21) next: MyId(22) next: MyId(23) Done -Steve
Re: Shared and race conditions
On Wednesday, 29 November 2017 at 16:33:50 UTC, Steven Schveighoffer wrote: On 11/29/17 11:13 AM, Wanderer wrote: [...] [snip] [...] Using the compiler switch -vcg-ast, I see no synchronization of these methods. [...] Any idea what has changed in DMD-nightly to retain the correct ordering of IDs?
Re: Shared and race conditions
On Wednesday, 29 November 2017 at 16:33:50 UTC, Steven Schveighoffer wrote: On 11/29/17 11:13 AM, Wanderer wrote: [...] [snip] [...] Using the compiler switch -vcg-ast, I see no synchronization of these methods. [...] That's what I assume, I was just lucky not to see a race. Thanks for `-vcg-ast` switch! Really helpful, and it answered my questions as no syncronization code was added.
Re: Shared and race conditions
On 11/29/17 11:13 AM, Wanderer wrote: I'm trying to simulate a race condition in D with the following code: [snip] But all I get is correct IDs without any sign of a race (i.e. duplicate ids). Does compiler add synchronization for `shared` data? Using the compiler switch -vcg-ast, I see no synchronization of these methods. Races are by definition unpredictable. What has to happen in your case is one of 2 things: 1. The thread context switches out after the next() call, but before the assignment. This is very very unlikely given the small number of instructions the thread executes (the OS isn't about to context switch out a thread it just switched into execution mode). 2. Two threads running on separate cores both assign at the exact same time, and they race on the data, one overwriting the other in memory. Note that executing 12 threads in concurrency isn't going to be a very stressful case for this race. Yes, it's probably more than the cores on your machine, but it's also a very small number of threads. Note also that even when there is a possibility of a race, it may be a long time before you see any errant behavior. I'd try more threads, and run the whole test in a loop. At the end of each loop iteration (after all the threads are completed), verify that the number has incremented by the correct amount. Stop only after it sees a race has happened. You may run for minutes until you see a race. You may never see one. That's the nature of the thing :) -Steve
Re: Shared and race conditions
On Wednesday, 29 November 2017 at 16:19:05 UTC, Michael wrote: On Wednesday, 29 November 2017 at 16:13:13 UTC, Wanderer wrote: [...] I unfortunately cannot answer your question but I am noticing that running the code with DMD gives you an unordered sequence of IDs, but running with DMD-nightly gives you a sequence in the correct order. I wonder what has changed to do with threads that causes this difference between compiler versions. The "unordered" output is completely fine, as I assume runtime does not guarantee the order of execution of logical threads (order is different between ldc and dmd as well).
Re: Shared and race conditions
On Wednesday, 29 November 2017 at 16:19:05 UTC, Michael wrote: On Wednesday, 29 November 2017 at 16:13:13 UTC, Wanderer wrote: [...] I unfortunately cannot answer your question but I am noticing that running the code with DMD gives you an unordered sequence of IDs, but running with DMD-nightly gives you a sequence in the correct order. I wonder what has changed to do with threads that causes this difference between compiler versions. Just to add to this, the page here: https://tour.dlang.org/tour/en/multithreading/synchronization-sharing does suggest that the compiler will automatically create critical sections when it can i.e. wrapping a section in synchronized { importStuff(); }
Re: Shared and race conditions
On Wednesday, 29 November 2017 at 16:13:13 UTC, Wanderer wrote: I'm trying to simulate a race condition in D with the following code: (https://run.dlang.io/is/RfOX0I) ``` import std.stdio; import core.thread; import std.concurrency; shared struct IdGen(T) { T id; this(T start) { id = start; } T next() { id = id.next(); return id; } } struct MyId { uint num; shared MyId next() { return MyId(num + 1); } } static void getId(shared IdGen!(MyId)* g) { writeln("next: ", g.next()); writeln("next: ", g.next()); } void main() { MyId start = {0}; auto g = IdGen!(MyId)(start); auto num = 12; for (auto i = 0; i < num; i++) { spawn(, ); } thread_joinAll(); writeln("Done"); } ``` But all I get is correct IDs without any sign of a race (i.e. duplicate ids). Does compiler add synchronization for `shared` data? I unfortunately cannot answer your question but I am noticing that running the code with DMD gives you an unordered sequence of IDs, but running with DMD-nightly gives you a sequence in the correct order. I wonder what has changed to do with threads that causes this difference between compiler versions.
Shared and race conditions
I'm trying to simulate a race condition in D with the following code: (https://run.dlang.io/is/RfOX0I) ``` import std.stdio; import core.thread; import std.concurrency; shared struct IdGen(T) { T id; this(T start) { id = start; } T next() { id = id.next(); return id; } } struct MyId { uint num; shared MyId next() { return MyId(num + 1); } } static void getId(shared IdGen!(MyId)* g) { writeln("next: ", g.next()); writeln("next: ", g.next()); } void main() { MyId start = {0}; auto g = IdGen!(MyId)(start); auto num = 12; for (auto i = 0; i < num; i++) { spawn(, ); } thread_joinAll(); writeln("Done"); } ``` But all I get is correct IDs without any sign of a race (i.e. duplicate ids). Does compiler add synchronization for `shared` data?
Re: Basic questions about D lang?
On Wednesday, 29 November 2017 at 11:32:51 UTC, Jayam wrote: In D lang, [...] 3. Can we make library file and use that in any project like 'Util class' ? Of course ! Plenty of them can be found here: https://code.dlang.org/?sort=updated=library
Re: Basic questions about D lang?
On Wednesday, 29 November 2017 at 11:32:51 UTC, Jayam wrote: In D lang, 1. Is there any feature async/ await like "c#" ? I can't find feature like async. As for me, async/await feature is a half-baked solution. With vibe-d you can write asynchronous code without thinking about it at all. Details: http://vibed.org/features 2. Is Garbage Collector work default without any code to force like in c# or do we need to manually trigger it ? It starts automatically when you try to allocate memory and there is no space in heap. In fact, it leads to architecture restriction: destructors must be @nogc. Also, you can run it with GC.collect() 3. Can we make library file and use that in any project like 'Util class' ? Yes.
Re: Basic questions about D lang?
On 29/11/2017 11:32 AM, Jayam wrote: In D lang, 1. Is there any feature async/ await like "c#" ? I can't find feature like async. No. The idea is floating around however. 2. Is Garbage Collector work default without any code to force like in c# or do we need to manually trigger it ? Automatic but if you want to be in control of it you can. 3. Can we make library file and use that in any project like 'Util class' ? Yes, but you don't need utility classes. They are a code smell (free-functions are the solution here).
Basic questions about D lang?
In D lang, 1. Is there any feature async/ await like "c#" ? I can't find feature like async. 2. Is Garbage Collector work default without any code to force like in c# or do we need to manually trigger it ? 3. Can we make library file and use that in any project like 'Util class' ?
Re: Strange error when compiling with dmd, not with ldc
On Wednesday, 29 November 2017 at 10:55:35 UTC, user1234 wrote: On Wednesday, 29 November 2017 at 06:18:09 UTC, Fra Mecca wrote: [...] You must also use a type constructor later, when a Configuration is declared: ``` immutable(Configuration) config; config.toString.writeln; // okay this time ``` What happens is that all the member functions have the `immutable` attribute, but the instance you declared was not itself `immutable`. actually this: ``` immutable struct Configuration { @property string toString(){return "";} } ``` is like: ``` struct Configuration { @property string toString() immutable {return "";} } ``` I would personally prefer the second form. Why ? Because the variable members will be set immutable anyway when an instance is declared. And about the DMD vs LDC thing, i thing that the difference can be simply explained by the fact that LDC uses a slightly older compiler front end version, meaning that after 1 or 2 updates, the same error would happen. Now i don't know which change in particular has been made recently in the front-end. Maybe the semantic of the leading qualifier when "immutable struct {}" is used but i would bet too much on that.
Re: Strange error when compiling with dmd, not with ldc
On Wednesday, 29 November 2017 at 06:18:09 UTC, Fra Mecca wrote: I have this struct: immutable struct Configuration { string title; string baseurl; string url; string email; string author; string parser; string target; string urlFormat; string urlFormatCmd; short port; string[] ignore; string[] extensions; @property string toString() { auto urlF = (urlFormatCmd ? "url_format_cmd: " ~ urlFormatCmd : "") ~ "\n"; return "title: "~ title ~ "\n" ~ "baseurl: " ~ baseurl ~ "\n" ~ "url: " ~ url ~ "\n" ~ "email: "~ email ~ "\n" ~ "author: " ~ author ~ "\n" ~ "parser: " ~ parser ~ "\n" ~ "target: " ~ target ~ "\n" ~ "url_format: " ~ urlFormat ~ "\n" ~ "ignore: " ~ to!string(ignore)[1 .. $ - 1] ~ "\n" ~ "extensions: " ~ to!string(extensions)[1 .. $ - 1] ~ "\n" ~ urlF; } } and this function: void show_config() { writef("%s", parse_config( exists("config.sdl") ? "config.sdl" : "").toString); } Whenever I compile with ldc2 I get no errors, while with dmd I get: source/configuration.d(105,27): Error: immutable method configuration.Configuration.toString is not callable using a mutable object What is the problem? You must also use a type constructor later, when a Configuration is declared: ``` immutable(Configuration) config; config.toString.writeln; // okay this time ``` What happens is that all the member functions have the `immutable` attribute, but the instance you declared was not itself `immutable`. actually this: ``` immutable struct Configuration { @property string toString(){return "";} } ``` is like: ``` struct Configuration { @property string toString() immutable {return "";} } ``` I would personally prefer the second form. Why ? Because the variable members will be set immutable anyway when an instance is declared.