Re: How to debug (potential) GC bugs?
Am Sun, 25 Sep 2016 16:23:11 + schrieb Matthias Klumpp : > So, I would like to know the following things: > > 1) Is there any caveat when linking to C libraries and using the > GC in a project? So far, it seems to be working well, but there > have been a few cases where I was suspicious about the GC > actually doing something to malloc'ed stuff or C structs present > in the bindings. If you pass callbacks into the C code, make sure they never throw. Stack unwinding and exception handling generally doesn't work across language boundaries. A tracing garbage collector starts with the assumption that all the memory that it allocated is no longer reachable and then starts scanning the known memory for any pointers to allocations that falsify this assumption. What you malloc'ed is unknown to the GC and wont be scanned. Should you ever have GC memory pointers in your malloc'ed stuff, then you need to call GC.addRange() to make those pointers keep the allocations alive. Otherwise you will get a "used after free" error: data corruption or access violations. A simple case would be a string that you constructed in D and store in C as a pointer. The GC can automatically scan the stack and any globals/statics on the D side, but that's about it. I know of no tools similar to valgrind specially designed to debug the D GC. You can plug into the GC API and keep track of the allocation sizes. I.e. write a proxy GC. -- Marco
Re: Easy sockets - don't exist yet?
Am Mon, 26 Sep 2016 23:40:10 + schrieb Vincent : > 1. Easy to use. No more stupid "UNIX sockets", "TCP types" and so > on. Just simple as this: > > // Client side > auto sock = new ClientSocket("google.com", 80); > sock.WriteLine("GET / HTTP/1.0"); > sock.WriteLine("Host: google.com"); > sock.WriteLine();// empty line sent Haha, this is not how I learned network layers at school. You seem to want on the ... Network Layer (3): A connection based socket using the Internet Protocol Transport Layer (4): A stateful connection using TCP Application Layer (6): HTTP Just that you don't ask for HTTP directly, but shoehorn a packet based socket into sending microscopic strings. In this case I recommend cURL, which you can feed with all the header data at once and sends your complete request in one packet. That'll also handle most of the HTTP specialties. Not all data transmissions via IP are TCP either. A good bunch is sent via stateless UDP. That would not be considered a stream though. I'm just getting at the name "ClientSocket" here, which can entail more than TCP/IP streams. -- Marco
Re: Easy sockets - don't exist yet?
Just in case, here are the relevant docs: http://dlang.org/phobos/std_net_curl.html
Problem parsing IPv4/IPv6 addresses with std.socket.parseAddress
Hi there! I wrote a small utility library to read configuration parameters from both command-line arguments (using std.getopt) and SDLang files (using sdlang-d package). The main library defines a struct ConfigParams whose fields are themselves structs defined in sub-libraries (set as dependencies), each responsible for reading one kind of parameter (BindAddress, BindPort, etc) from both command-line and SDL files. Each sub-library has its own unit tests which run successfully in isolation. Then, when putting everything together in the main struct CofigParams I get the compile-time error: /usr/include/dlang/dmd/std/socket.d(1195,9): Error: static variable getaddrinfoPointer cannot be read at compile time called from here: parseAddress(addressString, null) while using std.socket.parseAddress to validate IPv4/IPv6 bind addresses. I'm using dmd v2.071.2 and dub v1.0.0. The relevant piece of code where this happens is the following: struct BindAddress { import std.socket: parseAddress, SocketException; // Private members private string addressString = "0.0.0.0"; // Construct from address string this(string addressString) { try { auto address = parseAddress(addressString); } catch(SocketException ex) { throw new BindAddressException("Invalid bind address " ~ addressString); } this.addressString = addressString; } } As said, this works fine when tested in isolation, and the compiler only complains when using BindAddress as a member of ConfigParams. Any idea what the problem may be? Or is there maybe a ready to use, high-level library for parsing parameters from command-line arguments and config files of some kind?
Re: Easy sockets - don't exist yet?
Why not just create a binding to 0MQ and get much, much more than asked for? On Mon, 2016-09-26 at 23:40 +, Vincent via Digitalmars-d-learn wrote: > Hello, guys! > > I was very surprised that module 'socketstream' was deprecated. > Usually if something become obsolete, there is some perfect > replacement! But my digging in Inet and forums gave nothing, but > "outdated" examples with 'SocketStream' class. So first question > is WHAT Phobos has to replace SocketStream? > To avoid unnecessary mail bouncing, I write upfront what I expect > from normal Socket implementation (kind of interface) : > > 1. Easy to use. No more stupid "UNIX sockets", "TCP types" and so > on. Just simple as this: > > // Client side > auto sock = new ClientSocket("google.com", 80); > sock.WriteLine("GET / HTTP/1.0"); > sock.WriteLine("Host: google.com"); > sock.WriteLine();// empty line sent > > // Server side: > auto svc = new ServerSocket("Bound.To.This.IP", 1000); > while ((auto ClientSock = svc.AcceptClient()) !is null) { > auto command = ClientSock.ReadLine();// this is important - > read by line, not idiotic "buffers of bytes"! > ClientSock.WriteLine(command ~ ` yourself!`); > ClientSock.Close(); > } > > 2. Of course integration with std.stream could be nice, it gives > "for free" readLine and other methods. > 3. Ability to 'get and forget': hardly all of us wanna deal with > "get portion, write portion to disk, blah". Simple > "sock.ReceiveFile(`http://porno/girl.avi`, > `c:\diploma_work.avi`)" could be enough. > Some kind of "progress report" callback would be nice. > 4. SSL/TLS out-of-the-box. In example above it should be same > easy as: > > auto sock = new ClientSocket("google.com", 80, Proto.TLS); > > > At the moment it's all I need, but hope you'll be happy too with > such interface. Sockets are SOOO important, that I cannot believe > we don't have so easy API now. Or if we have, please share! > > Thanks everybody! > -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Is there any way to have [] overloads use compile-time indexes as is currently done for Tuples?
I'd really like to define my own types that accept indexes for opIndex and opSlice as template arguments. Is there any way to do this? If not, this seems like an obvious thing to add to the language - what's been holding it back?
Re: Easy sockets - don't exist yet?
On Tuesday, 27 September 2016 at 09:23:35 UTC, Russel Winder wrote: Why not just create a binding to 0MQ and get much, much more than asked for? http://code.dlang.org/packages/zmqd http://code.dlang.org/packages/zeromq http://code.dlang.org/packages/dzmq or use existing ones :)
JSON decode?
Hi, from a rest call I get a JSON with a strange format: {"DEPLOY_ATTRIBUTES":"{\n \"dependency-type\": \"soft\"\n}","MTA_METADATA":"{\n \"id\":... The sub objects are enclosed with quotes and there are a lot of line break characters. Also the quotes are escaped. I try to translate a Python script which has no issues to handle this JSON correctly, but I do not understand why. Python seems to handle this with decode('utf-8')? Is there some functionality in Phobos to handle this format correctly? Kind regards André
Re: Easy sockets - don't exist yet?
On Tue, 2016-09-27 at 10:16 +, JN via Digitalmars-d-learn wrote: > On Tuesday, 27 September 2016 at 09:23:35 UTC, Russel Winder > wrote: > > > > Why not just create a binding to 0MQ and get much, much more > > than asked for? > > > > http://code.dlang.org/packages/zmqd > http://code.dlang.org/packages/zeromq > http://code.dlang.org/packages/dzmq > > or use existing ones :) Even better, except it would be good if there was one. Maybe the authors of these three can get together and make a single binding to avoid dispersion. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Easy sockets - don't exist yet?
On Tuesday, 27 September 2016 at 11:16:00 UTC, Russel Winder wrote: On Tue, 2016-09-27 at 10:16 +, JN via Digitalmars-d-learn wrote: On Tuesday, 27 September 2016 at 09:23:35 UTC, Russel Winder wrote: > > Why not just create a binding to 0MQ and get much, much more > than asked for? > http://code.dlang.org/packages/zmqd http://code.dlang.org/packages/zeromq http://code.dlang.org/packages/dzmq or use existing ones :) Even better, except it would be good if there was one. Maybe the authors of these three can get together and make a single binding to avoid dispersion. Not really, because some of these are just pure C bindings, while some offer D wrappers for the ZeroMQ interface. Both are good to have, depending on the needs.
Re: JSON decode?
On Tuesday, 27 September 2016 at 10:45:45 UTC, Andre Pany wrote: Hi, from a rest call I get a JSON with a strange format: {"DEPLOY_ATTRIBUTES":"{\n \"dependency-type\": \"soft\"\n}","MTA_METADATA":"{\n \"id\":... The sub objects are enclosed with quotes and there are a lot of line break characters. Also the quotes are escaped. I try to translate a Python script which has no issues to handle this JSON correctly, but I do not understand why. Python seems to handle this with decode('utf-8')? Is there some functionality in Phobos to handle this format correctly? Kind regards André OK, I found the solution. There is no magic in python. For these kinds of attributes the python code checks whether it is a string, and then tries to parse again as JSON, wired! Kind regards André
Re: Is there any way to have [] overloads use compile-time indexes as is currently done for Tuples?
On Tuesday, 27 September 2016 at 09:21:04 UTC, pineapple wrote: I'd really like to define my own types that accept indexes for opIndex and opSlice as template arguments. Is there any way to do this? If not, this seems like an obvious thing to add to the language - what's been holding it back? https://issues.dlang.org/show_bug.cgi?id=16302
Re: How to debug (potential) GC bugs?
On Sunday, 25 September 2016 at 16:23:11 UTC, Matthias Klumpp wrote: Hello! I am working together with others on the D-based appstream-generator[1] project, which is generating software metadata for "software centers" and other package-manager functionality on Linux distributions, and is used by default on Debian, Ubuntu and Arch Linux. For Ubuntu, some modifications on the code were needed, and apparently for them the code is currently crashing in the GC collection thread: http://paste.debian.net/840490/ The project is running a lot of stuff in parallel and is using the GC (if the extraction is a few seconds slower due to the GC being active, it doesn't matter much). We also link against a lot of 3rd-party libraries and use a big amount of existing C code in the project. So, I would like to know the following things: 1) Is there any caveat when linking to C libraries and using the GC in a project? So far, it seems to be working well, but there have been a few cases where I was suspicious about the GC actually doing something to malloc'ed stuff or C structs present in the bindings. There is no way the GC scans memory allocated with malloc (unless you tell it to) or used in the bindings. A caveat is that if you are called from C (not your case), you must initialize the runtime, and attach/detach threads. The GC could well stop threads that are currently in the C code if they were registered to the runtime. 2) How can one debug issues like the one mentioned above properly? Since it seems to happen in the GC and doesn't give me information on where to start searching for the issue, I am a bit lost. There can be multiple reasons. - The GC is collecting some object that is unreachable from its POV; when you are actually using it. - The GC is calling destructors, that should not be called by the GC. Performing illegal operations. usually this is solved by using deterministic destruction instead and never relying on a destructor called by the GC. - The GC tries to stop threads that don't exist anymore or are not interruptible My advice is to have a fuly deterministic tree of objects, like a C++ program, and Google for "GC-proof resource class" in case you are using classes.
Re: Module Clarification
On 9/22/16 4:16 PM, Jonathan Marler wrote: On Thursday, 22 September 2016 at 20:09:41 UTC, Steven Schveighoffer wrote: Before package.d support, you could not do any importing of packages. You could only import modules. package.d was how the compiler allowed importing packages. I don't know that there is a fundamental difference between foo/package.d and foo.d, but this is just the solution that was chosen. Is it a mistake? I don't think so, it's just a preference. Prior to this, it was common to put "package" imports into an "all.d" file: foo/all.d // import fooPart1.d fooPart2.d foo/fooPart1.d Ok, do you know why is this not allowed? I'm sure if you search the forums, you can find discussions of this. Walter probably had a reason. I'm not sure if the reason is valid anymore now that package.d is supported. -Steve
Re: Proper way to work around `Invalid memory operation`?
On Sunday, 25 September 2016 at 16:07:12 UTC, Matthias Klumpp wrote: Hello! I have a class similar to this one: ``` class Dummy { private: string tmpDir; public: this (string fname) { tmpDir = buildPath ("/tmp", fname.baseName); std.file.mkdirRecurse (tmpDir); } ~this () { close (); } void close () { if (std.file.exists (tmpDir)) std.file.rmdirRecurse (tmpDir); } } ``` When the GC calls the classes destructor, I get a `core.exception.InvalidMemoryOperationError@/<...>/ldc/runtime/druntime/src/core/exception.d(693): Invalid memory operation` Looks like rmdirRecurse tries to allocate with the GC, and the GC doesn't like that. Is there any good way to get the temporary directory deletet automatically when the object is freed? At time, I work around this bug by calling close() manually at the appropriate time, but this feel like a rather poor solution. Cheers, Matthias As seen, you can't make GC allocations in dtors. And you should never rely on the GC calling your dtor to close things like file handles anyways. Consider making Dummy a struct and maybe using std.typecons(?).RefCounted with it.
Re: How to debug (potential) GC bugs?
On Sunday, 25 September 2016 at 16:23:11 UTC, Matthias Klumpp wrote: Hello! I am working together with others on the D-based appstream-generator[1] project, which is generating software metadata for "software centers" and other package-manager functionality on Linux distributions, and is used by default on Debian, Ubuntu and Arch Linux. For Ubuntu, some modifications on the code were needed, and apparently for them the code is currently crashing in the GC collection thread: http://paste.debian.net/840490/ The project is running a lot of stuff in parallel and is using the GC (if the extraction is a few seconds slower due to the GC being active, it doesn't matter much). We also link against a lot of 3rd-party libraries and use a big amount of existing C code in the project. So, I would like to know the following things: 1) Is there any caveat when linking to C libraries and using the GC in a project? So far, it seems to be working well, but there have been a few cases where I was suspicious about the GC actually doing something to malloc'ed stuff or C structs present in the bindings. 2) How can one debug issues like the one mentioned above properly? Since it seems to happen in the GC and doesn't give me information on where to start searching for the issue, I am a bit lost. 3) The tool seems to leak memory somewhere and OOMs pretty quickly on some machines. All the stuff using C code frees resources properly though, and using Valgrind on the project is a pain due to large amounts of data being mmapped. I worked around this a while back, but then the GC interfered with Valgrind, making information less useful. Is there any information on how to find memory leaks, or e.g. large structs the GC cannot free because something is still having a needless reference on it? Unfortunately I can't reproduce the crash from 2) myself, it only seems to happen at Ubuntu (but Ubuntu is using some different codepaths too). Any insights would be highly appreciated! Cheers, Matthias [1[: https://github.com/ximion/appstream-generator First, make sure any C threads calling D code use Thread.attachThis (thread_attachThis maybe?). Otherwise the GC will not suspend those threads during a collection which will cause crashes. I'd guess this is your issue. Second, tell the GC of non-GC memory that has pointers to GC memory by using GC.addRange / GC.addRoot as needed. Make sure to remove them once the non-GC memory is deallocated as well, otherwise you'll get memory leaks. The GC collector is also conservative, not precise, so false positives are possible. If you're using 64 bit programs, this shouldn't be much of an issue though. Finally, make sure you're not doing any GC allocations in dtors.
Re: Problem parsing IPv4/IPv6 addresses with std.socket.parseAddress
On Tuesday, 27 September 2016 at 09:04:53 UTC, Dsciple wrote: As said, this works fine when tested in isolation, and the compiler only complains when using BindAddress as a member of ConfigParams. Any idea what the problem may be? Or is there maybe a ready to use, high-level library for parsing parameters from command-line arguments and config files of some kind? I assume your ConfigParams variable is global or static? Can you show how you initialize it, and how it's declared? You're probably using it in a way that requires it to be evaluated at compile time. That's the case for initializers of global/static variables, as well as default values of struct members.
Re: Problem parsing IPv4/IPv6 addresses with std.socket.parseAddress
On Tuesday, 27 September 2016 at 14:02:25 UTC, Marc Schütz wrote: On Tuesday, 27 September 2016 at 09:04:53 UTC, Dsciple wrote: As said, this works fine when tested in isolation, and the compiler only complains when using BindAddress as a member of ConfigParams. Any idea what the problem may be? Or is there maybe a ready to use, high-level library for parsing parameters from command-line arguments and config files of some kind? I assume your ConfigParams variable is global or static? Can you show how you initialize it, and how it's declared? You're probably using it in a way that requires it to be evaluated at compile time. That's the case for initializers of global/static variables, as well as default values of struct members. Yes I think so. I use static default values for all members of ConfigParams and I instantiate ConfigParams in my unit tests, so I assume that the variable would be global there. The code looks like: unittest { string[] args = [ "binaryFileName", "--bindAddresses=0.1.2.3;4.5.6.7", "--bindHTTPPort=80", "--bindHTTPSPort=443", "--configFile=testfiles/test.conf.sdl", "--verbosityLevel=detailed", ]; ConfigParams configParams; // default values for parameters configParams.readFromAll(args); // values read from command-line arguents // assertion checks here } What do you suggest? Should I move all default initializations to a constructor? Thank you for your response.
Re: Problem parsing IPv4/IPv6 addresses with std.socket.parseAddress
On Tuesday, 27 September 2016 at 14:39:10 UTC, Dsciple wrote: On Tuesday, 27 September 2016 at 14:02:25 UTC, Marc Schütz wrote: On Tuesday, 27 September 2016 at 09:04:53 UTC, Dsciple wrote: As said, this works fine when tested in isolation, and the compiler only complains when using BindAddress as a member of ConfigParams. Any idea what the problem may be? Or is there maybe a ready to use, high-level library for parsing parameters from command-line arguments and config files of some kind? I assume your ConfigParams variable is global or static? Can you show how you initialize it, and how it's declared? You're probably using it in a way that requires it to be evaluated at compile time. That's the case for initializers of global/static variables, as well as default values of struct members. Yes I think so. I use static default values for all members of ConfigParams and I instantiate ConfigParams in my unit tests, so I assume that the variable would be global there. The code looks like: unittest { string[] args = [ "binaryFileName", "--bindAddresses=0.1.2.3;4.5.6.7", "--bindHTTPPort=80", "--bindHTTPSPort=443", "--configFile=testfiles/test.conf.sdl", "--verbosityLevel=detailed", ]; ConfigParams configParams; // default values for parameters configParams.readFromAll(args); // values read from command-line arguents // assertion checks here } What do you suggest? Should I move all default initializations to a constructor? Thank you for your response. I forgot to show declaration. Here it is: struct ConfigParams { import ConfigParamsCLAMixin: ConfigParamsCLA; import ConfigParamsSDLMixin: ConfigParamsSDL; import ConfigParamsAllMixin: ConfigParamsAll; import BindAddress: BindAddress, BindAddressException; import BindAddresses: BindAddresses, BindAddressesException; import BindPort: BindPort, BindPortException; import PosixPath: PosixPath, PosixPathException; import VerbosityLevel: VerbosityLevel, VerbosityLevelException; // Define configuration parameters' static default fields static immutable BindAddresses defaultBindAddresses = BindAddresses([ BindAddress("192.168.2.10") ]); static immutable BindPort defaultBindHTTPPort = BindPort(8080); static immutable BindPort defaultBindHTTPSPort = BindPort(4430); static immutable PosixPath defaultConfigFile = PosixPath("/etc/ras/ras.conf.sdl"); static immutable VerbosityLevel defaultVerbosityLevel = VerbosityLevel("quiet"); // Define configuration parameters fields with default values BindAddresses bindAddresses = defaultBindAddresses; BindPort bindHTTPPort = defaultBindHTTPPort; BindPort bindHTTPSPort = defaultBindHTTPSPort; PosixPath configFile = defaultConfigFile; VerbosityLevel verbosityLevel = defaultVerbosityLevel; } I don't understand why the unit tests of all individual members of ConfigParams (BindAddresses, BindAddress and so on) would work in isolation using the same kind of initialization, whereas some of them would fail as members of ConfigParams. I suspect this may also be a problem with settings in dub.json for ConfigParams: { ... "sourcePaths": [ "sources" ], "importPaths": [ "sources" ], "configurations": [ { "name": "library", "targetName": "ConfigParams", "targetType": "library" } ], "dependencies": { "bind-address": { "version": "*", "path": "./libraries/BindAddress" }, "bind-addresses": { "version": "*", "path": "./libraries/BindAddresses" }, "bind-port": { "version": "*", "path": "./libraries/BindPort" }, "posix-name": { "version": "*", "path": "./libraries/PosixName" }, "posix-path": { "version": "*", "path": "./libraries/PosixPath" }, "verbosity-level": { "version": "*", "path": "./libraries/VerbosityLevel" } } if I include bind-address as a dependency (as above), dub refuses to run with: Sub package bind-address: doesn't exist. although the package is there and used by bind-addresses and confi params too...
Re: Module Clarification
On Tuesday, 27 September 2016 at 13:48:39 UTC, Steven Schveighoffer wrote: On 9/22/16 4:16 PM, Jonathan Marler wrote: On Thursday, 22 September 2016 at 20:09:41 UTC, Steven Schveighoffer wrote: Before package.d support, you could not do any importing of packages. You could only import modules. package.d was how the compiler allowed importing packages. I don't know that there is a fundamental difference between foo/package.d and foo.d, but this is just the solution that was chosen. Is it a mistake? I don't think so, it's just a preference. Prior to this, it was common to put "package" imports into an "all.d" file: foo/all.d // import fooPart1.d fooPart2.d foo/fooPart1.d Ok, do you know why is this not allowed? I'm sure if you search the forums, you can find discussions of this. Walter probably had a reason. I'm not sure if the reason is valid anymore now that package.d is supported. -Steve foo.d foo/bar.d I would think the reason for not supporting this is you wouldn't want something to be a "module" and a "package" at the same time, but introduction of the "package.d" semantics has broken that rule. From what I can see, it seems like the concept of "packages" doesn't have any useful meaning anymore. Before adding "package.d" support, a "package" was a directory/node you could find modules underneath, but now that it can also be a module itself, saying something is a "package" doesn't really have any meaning. Take the following 2 cases: Case 1: foo.d Case 2: foo/package.d In case 1, foo is a "module", and in case 2, foo is a "package". The problem is that foo can behave EXACTLY THE SAME in both cases. foo could contain typical module code, or publicly import other modules like a typical "package.d" file, in both cases. Saying that foo is a "package" doesn't tell you anything about how "foo" behaves. The "package" concept seems pretty meaningless now.
Is TDPL an accurate description of the D language today?
I've been going through Andrei's excellent book and I noticed that the latest printing is from 2010. Since D is still a very young language I can imagine it changing quite a bit within six years. So I wonder if there are any major inconsistincies between the current state of the language and its description in TDPL. Is there a list somewhere with all the changes made in the langauge since the book was published? Thanks a lot.
Re: Is TDPL an accurate description of the D language today?
On 9/27/16 1:38 PM, Mark wrote: I've been going through Andrei's excellent book and I noticed that the latest printing is from 2010. Since D is still a very young language I can imagine it changing quite a bit within six years. So I wonder if there are any major inconsistincies between the current state of the language and its description in TDPL. Is there a list somewhere with all the changes made in the langauge since the book was published? Thanks a lot. Most things that are "wrong" in the book should be in the errata: http://erdani.com/tdpl/errata/ There are also some things that are not wrong in the book, but have not been implemented. I think the most glaring difference is that "clear" has been renamed to "destroy". -Steve
Re: Lazily evaluated property pointing to read only object
On Saturday, 24 September 2016 at 11:51:56 UTC, Basile B. wrote: On Saturday, 24 September 2016 at 10:59:50 UTC, mikey wrote: On Saturday, 24 September 2016 at 10:16:34 UTC, Basile B. wrote: You don't need to cast, from "mutable" to "const" is implicit: https://dlang.org/spec/const3.html#implicit_conversions Ok, but using const would be an accepted way of doing this? The options I could see were to have "_o" as a const or immutable type and just create a const on the first call to the lazily evaluated property, or to do what I did and have "_o" as a non-const and then convert it to cost on the way out. However To store it as const I guess I'd have to make it a non-const pointer to a const object, and is that not kind of what immutable is? Yes, the problem is that if you want to create a true const(Object) (with const part of the type) you have to initialize it in a constructor (so no lazyness). It indeed looks like the immutable mechanism. I don't know **exactly** why but I guess that's a special case for classes since there's no other way to initialize them. Finally, with the property your object is seen as const(Object) outside. The only difference is inside ConstProp. use Rebindable: class Obj { string _s; this()pure{ this(""); } this(string s)pure{ _s = s; } @property string desc() const { return _s; } @property void desc(string s) { _s = s; } override string toString() const { return _s; } } class ConstProp { import std.typecons : Rebindable; Rebindable!(immutable Obj) _o; string _s; this(string s) { _s = s; } immutable(Obj) lazily(){ if (_o is null) { _o = new Obj("working " ~ _s); } return _o; } }
Usage of DDOC_KEYWORD and DDOC_TEMPLATE_PARAM macros
I'm working on a Ddoc theme and I have trouble figuring out when the DDOC_KEYWORD and DDOC_TEMPLATE_PARAM macros are used. Are the compiler outputting them or should the developer be using those directly? If the compiler is outputting them, then when is it doing that? -- /Jacob Carlborg
Macintosh text file with invalid line breaks are created
Hi, following application creates a text file with strange content: void writeTextFile(string filePath, string text) { import std.stdio: File; auto f = File(filePath, "w"); f.write(text); f.close(); } void main() { import std.ascii: newline; string s = "a=1"~newline~"b=2"; writeTextFile("./test.txt", s); } Notepad++ detects the file as macintosh UTF8 file. The file has following content: a=1CR CRLF b=2 Where the first CR comes from? Is this a bug? dmd v2.071.2 on win10 Kind regards André