Re: implicit or module-wide @nogc
On Wednesday, 13 June 2018 at 07:11:56 UTC, Mike Franklin wrote: On Wednesday, 13 June 2018 at 06:45:27 UTC, Gokhhy wrote: Is there a way to define an entire module as @nogc or otherwise make it so I don't have to qualify every single function as @nogc? You can put attributes at the top of a module followed by a ":" to have them apply to everything below them. module mymodule; @nogc: void nogcFunction1() { } void nogcFunction2() { } Mike Thanks, just what I was looking for.
Re: implicit or module-wide @nogc
On Wednesday, 13 June 2018 at 06:45:27 UTC, Gokhhy wrote: Is there a way to define an entire module as @nogc or otherwise make it so I don't have to qualify every single function as @nogc? You can put attributes at the top of a module followed by a ":" to have them apply to everything below them. module mymodule; @nogc: void nogcFunction1() { } void nogcFunction2() { } Mike
Re: implicit or module-wide @nogc
On Wednesday, 13 June 2018 at 06:45:27 UTC, Gokhhy wrote: Is there a way to define an entire module as @nogc or otherwise make it so I don't have to qualify every single function as @nogc? --- module module_wide-nogc; @nogc: /* declarations or statements... */ --- But this is not considered as a good practice. 1. One can work on the module and miss the global nogc 2. unittest are affected (array literals for example must be declared static immutable) 3. it cannot be temporarily canceled. It depends on the context too. 200 slocs module or 5000 sloc module ? for a small one this could be ok.
Re: implicit or module-wide @nogc
On Wednesday, 13 June 2018 at 07:14:35 UTC, Gokhhy wrote: On Wednesday, 13 June 2018 at 07:11:56 UTC, Mike Franklin wrote: On Wednesday, 13 June 2018 at 06:45:27 UTC, Gokhhy wrote: Is there a way to define an entire module as @nogc or otherwise make it so I don't have to qualify every single function as @nogc? You can put attributes at the top of a module followed by a ":" to have them apply to everything below them. module mymodule; @nogc: void nogcFunction1() { } void nogcFunction2() { } Mike Thanks, just what I was looking for. Nevermind, it doesn't affect functions inside classes and structs. I would be interested in what influenced the design decision to make opting out of garbage collection so difficult.
Re: implicit or module-wide @nogc
On Wednesday, 13 June 2018 at 07:19:24 UTC, Gokhhy wrote: Nevermind, it doesn't affect functions inside classes and structs. Yeah, that's kindof unfortunate isn't it. Just do the same thing within the class/struct scope. class C { @nogc: void nogcMethod1() {} void nogcMehtod2() {} } I would be interested in what influenced the design decision to make opting out of garbage collection so difficult. Because D is more evolution then intelligent design, unfortunately. Mike
Class qualifier vs struct qualifier
Hello, I'm having a hard time understanding whether this inconsistency is a bug or intended behavior: immutable class Foo {} immutable struct Bar {} void main() { import std.stdio : writeln; Foo a; Bar b; writeln("typeof(a): ", typeof(a).stringof); writeln("typeof(b): ", typeof(b).stringof); } prints: typeof(Foo): Foo typeof(Bar): immutable(Bar) It seems like the class storage class is not taken into account which leads to some awkward situations like: immutable class Foo { this() {} } void main() { Foo a = new Foo(); // error: immutable method `this` is not callable using a // mutable object } To make it work I have to add immutable to both sides of the expression : immutable Foo a = new immutable Foo(); this is a wonder of redundancy. I already declared the class as immutable so it shouldn't be possible to have mutable instances of it (and it isn't), however I am forced to write the immutable twice even though it is pretty obvious that the class cannot be mutated.
Re: What is the point of nothrow?
On Wednesday, 13 June 2018 at 03:14:33 UTC, Jonathan M Davis wrote: Most programs do not handle the case where they run out of memory and cannot continue at that point. For better or worse, D's GC was designed with that in mind, and it treats failed allocations as an Error. In the vast majority of cases, this is desirable behavior. In those cases when it isn't, alternate memory allocation schemes such as malloc can be used. But But manual memory management sucks and is a huge waste of everyone's time and I was hoping to get the best from both worlds :) regardless of whether the decision to treat failed memory allocations as an Error was a good one or not, the fact remains that as soon as an Error is thrown, you lose the ability to deal with things cleanly, because full clean up is not done when an Error is thrown (and can't be due to things like how nothrow works). So, regardless of whether a failed memory allocation is a condition that can be recovered from in principle, the way that D handles GC allocations make it unrecoverable in practice - at least as far as GC-allocated memory is concerned. Did I get that right? You say when an error is thrown destructors, scope statements, etc. are not executed - if declared as nothrow because the exception handler mechanism stuff is missing, is that correct? And it does execute if not declared as nothrow but can't be relied upon because some other nothrow functions could have omitted some of those statements? So I shoot myself in the foot with nothrow and if I don't use it I'm still in a world of hurt? I understand the idea that an Error is not supposed to be caught but why would such a 'feature' be desirable? Where's the benefit if nothing can be relied upon ? If all errors would be treated like an exception, the developer could decide whether it is an error which needs to terminate right away or be able to handle the issue and continue or gracefully shutdown. Could even set a break point or force a core dump right there. If the exception would be ignored the program will crash regardless but at least there would be a stack trace that I could rely upon instead of this unreliable and possibly corrupt state which is good for nothing. This concept is a bit like color everyone with the same brush or one shoe fits all. Where in reality it depends on the circumstances whether it is an error or an exception. But maybe I feel that way because currently there's a bit of a blur regarding what's defined as Errors and Exceptions. Anyways I took a lot from your awesome explanations so far. Thanks a ton!
Pass arguments at compile time
I want to import a config file at compile time, but also need a way to have multiple configurations. With gcc you could do something like -DIMPORTFROM='"MyConfigFile.txt"'. Is there any equivalent in D? Hardcoding the config files for different versions and using that is not an option. Requiring a fixed filename and using different paths to configure with -J wouldn't be a good solution for my specific situation either. So far my best idea was to write the wanted filename to a file and import twice. enum config = import(import("importFrom.txt")); That works, but that is additional work for the build script and feels like a hack.
Re: Pass arguments at compile time
On Wednesday, 13 June 2018 at 10:57:27 UTC, Malte wrote: I want to import a config file at compile time, but also need a way to have multiple configurations. With gcc you could do something like -DIMPORTFROM='"MyConfigFile.txt"'. Is there any equivalent in D? Hardcoding the config files for different versions and using that is not an option. Requiring a fixed filename and using different paths to configure with -J wouldn't be a good solution for my specific situation either. So far my best idea was to write the wanted filename to a file and import twice. enum config = import(import("importFrom.txt")); That works, but that is additional work for the build script and feels like a hack. If you're using dub just specify "stringImportPath" as a folder to the configuration files. You can't retrieve the files though, so you'd need to know the names of the files you want to use. However if they're located in the path then you can just do enum config = import("MyconfigFile.txt");
Re: What is the point of nothrow?
On Tuesday, 12 June 2018 at 14:15:42 UTC, Steven Schveighoffer wrote: I predict at some point when Errors actually don't do proper cleanup, it is going to be a really difficult time for D. Looks like it already doesn't: https://run.dlang.io/is/OhDwtW
Re: What is the point of nothrow?
On Wednesday, 13 June 2018 at 02:02:54 UTC, wjoe wrote: it is possible to install a signal handler for almost every signal on POSIX, including segfault. The only signal you can't catch is signal 9 - sigkill if memory serves. So I could for instance install a clean up handler on a segfault via memset, or a for loop, and then terminate. What will you do with this? https://github.com/dlang/druntime/blob/master/src/core/internal/abort.d
Re: What is the point of nothrow?
On Wednesday, 13 June 2018 at 10:56:41 UTC, wjoe wrote: I understand the idea that an Error is not supposed to be caught but why would such a 'feature' be desirable? Where's the benefit if nothing can be relied upon ? It's a debugging facility for development stage that allows to print the error message and stack trace instead of silent termination. Because it still needs to be caught for this, explicit catch still works, but other cleanup mechanisms don't.
Passing struct to function
When I pass my struct to function something is going wrong. I don't know how to fix it. Code: import std.stdio; void print(ref Vector v, string s){ writefln("%s==%s%s", &v.x, v.ptr, s); } struct Vector { int x; int* ptr; this(this) { ptr = &x; print(this, "postblit"); } } void someFunc(Vector t) { print(t, "in someFunc"); } void main() { auto tmpA = Vector(); tmpA.ptr = &tmpA.x; print(tmpA, "start"); someFunc(tmpA); } Result on my machine: 7FFF7D70BC00==7FFF7D70BC00start 7FFF7D70BBF0==7FFF7D70BBF0postblit 7FFF7D70BBD0==7FFF7D70BBF0in someFunc In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time?
Docs for subpackages?
Hi, I am trying to build a large project that is split into dozen of sub-packages. How I can do it using dub without writing my own doc scripts? --combined does not help here. Best regards, Ilya
Re: remove not callable for char[]
On 6/13/18 1:18 AM, Flaze07 wrote: I see, so it means that only char is affected, gotcha Well, char[] and wchar[]. dchar[] is treated as an array by Phobos. But calling byCodeUnit on a dchar array should work just like an array as well, so using it is the most generic solution. -Steve
Re: implicit or module-wide @nogc
On 6/13/18 3:24 AM, Mike Franklin wrote: Because D is more evolution then intelligent design, unfortunately. I had to LOL on this, nice :) -Steve
Re: Class qualifier vs struct qualifier
On 6/13/18 3:35 AM, RazvanN wrote: Hello, I'm having a hard time understanding whether this inconsistency is a bug or intended behavior: immutable class Foo {} immutable struct Bar {} void main() { import std.stdio : writeln; Foo a; Bar b; writeln("typeof(a): ", typeof(a).stringof); writeln("typeof(b): ", typeof(b).stringof); } prints: typeof(Foo): Foo typeof(Bar): immutable(Bar) It seems like the class storage class is not taken into account which leads to some awkward situations like: immutable class Foo { this() {} } void main() { Foo a = new Foo(); // error: immutable method `this` is not callable using a // mutable object } To make it work I have to add immutable to both sides of the expression : immutable Foo a = new immutable Foo(); this is a wonder of redundancy. I already declared the class as immutable so it shouldn't be possible to have mutable instances of it (and it isn't), however I am forced to write the immutable twice even though it is pretty obvious that the class cannot be mutated. Just on the principle of least surprise, I'd call this a bug. I don't know what the intention is, but if the intention is for this behavior, we should re-visit. -Steve
Re: What is the point of nothrow?
On 6/13/18 8:44 AM, Kagamin wrote: On Tuesday, 12 June 2018 at 14:15:42 UTC, Steven Schveighoffer wrote: I predict at some point when Errors actually don't do proper cleanup, it is going to be a really difficult time for D. Looks like it already doesn't: https://run.dlang.io/is/OhDwtW Damn, that's interesting. And it's been that way since 2.061! So much for my shitty predictions :) BTW, Seb, I edited this to change it to Exception to see what happens, and then I wanted to re-run the original, so I closed it and re-clicked on the link, and it brought up my EDITED code. I had to clear the cookies on run.dlang.io from my browser to get it to restore. This is quite annoying, can it be fixed? -Steve
Re: Passing struct to function
On 6/13/18 10:43 AM, Michał wrote: When I pass my struct to function something is going wrong. I don't know how to fix it. Code: import std.stdio; void print(ref Vector v, string s){ writefln("%s==%s %s", &v.x, v.ptr, s); } struct Vector { int x; int* ptr; this(this) { ptr = &x; print(this, "postblit"); } } void someFunc(Vector t) { print(t, "in someFunc"); } void main() { auto tmpA = Vector(); tmpA.ptr = &tmpA.x; print(tmpA, "start"); someFunc(tmpA); } Result on my machine: 7FFF7D70BC00==7FFF7D70BC00 start 7FFF7D70BBF0==7FFF7D70BBF0 postblit 7FFF7D70BBD0==7FFF7D70BBF0 in someFunc In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time? D allows moving any struct instance without calling postblit, as long as the original is no longer used. The optimizer is likely seeing here that the memory can be copied without calling postblit, because nobody is using tmpA after the call. In general, you should NOT store an internal pointer in a struct, unless you allocate it on the heap. -Steve
Re: What is the point of nothrow?
On Wednesday, 13 June 2018 at 12:59:27 UTC, Kagamin wrote: On Wednesday, 13 June 2018 at 02:02:54 UTC, wjoe wrote: it is possible to install a signal handler for almost every signal on POSIX, including segfault. The only signal you can't catch is signal 9 - sigkill if memory serves. So I could for instance install a clean up handler on a segfault via memset, or a for loop, and then terminate. What will you do with this? https://github.com/dlang/druntime/blob/master/src/core/internal/abort.d Are you asking what I would do in case sigabrt is received by my program instead of sigsegv ? I would install the same cleanup functionality in this handler. Zero out memory, send a signal to stop an engine or whatever mandatory clean up is required and return from the handler. Then let the OS take care of the rest, i.e. terminate the process.
Re: What is the point of nothrow?
On Wednesday, 13 June 2018 at 13:05:44 UTC, Kagamin wrote: On Wednesday, 13 June 2018 at 10:56:41 UTC, wjoe wrote: I understand the idea that an Error is not supposed to be caught but why would such a 'feature' be desirable? Where's the benefit if nothing can be relied upon ? It's a debugging facility for development stage that allows to print the error message and stack trace instead of silent termination. Because it still needs to be caught for this, explicit catch still works, but other cleanup mechanisms don't. My question was more like what's the benefit of having thrown Errors corrupt your program state rendering it useless for debugging ?
Re: Passing struct to function
On Wednesday, 13 June 2018 at 16:40:51 UTC, Steven Schveighoffer wrote: On 6/13/18 10:43 AM, Michał wrote: When I pass my struct to function something is going wrong. I don't know how to fix it. Code: import std.stdio; void print(ref Vector v, string s){ writefln("%s==%s %s", &v.x, v.ptr, s); } struct Vector { int x; int* ptr; this(this) { ptr = &x; print(this, "postblit"); } } void someFunc(Vector t) { print(t, "in someFunc"); } void main() { auto tmpA = Vector(); tmpA.ptr = &tmpA.x; print(tmpA, "start"); someFunc(tmpA); } Result on my machine: 7FFF7D70BC00==7FFF7D70BC00 start 7FFF7D70BBF0==7FFF7D70BBF0 postblit 7FFF7D70BBD0==7FFF7D70BBF0 in someFunc In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time? D allows moving any struct instance without calling postblit, as long as the original is no longer used. The optimizer is likely seeing here that the memory can be copied without calling postblit, because nobody is using tmpA after the call. In general, you should NOT store an internal pointer in a struct, unless you allocate it on the heap. -Steve I need internal pointer because I want to implement vector(like in C++) with 'small vector optimization', when i have internal pointer it is very easy and functions like 'add' don't have additional checks. If storing internal pointers is forbidden do you know some way to implement 'small vector optimization' without additional checks in 'add' function?
Re: Passing struct to function
On 6/13/18 1:08 PM, Michał wrote: On Wednesday, 13 June 2018 at 16:40:51 UTC, Steven Schveighoffer wrote: On 6/13/18 10:43 AM, Michał wrote: When I pass my struct to function something is going wrong. I don't know how to fix it. Code: import std.stdio; void print(ref Vector v, string s){ writefln("%s==%s %s", &v.x, v.ptr, s); } struct Vector { int x; int* ptr; this(this) { ptr = &x; print(this, "postblit"); } } void someFunc(Vector t) { print(t, "in someFunc"); } void main() { auto tmpA = Vector(); tmpA.ptr = &tmpA.x; print(tmpA, "start"); someFunc(tmpA); } Result on my machine: 7FFF7D70BC00==7FFF7D70BC00 start 7FFF7D70BBF0==7FFF7D70BBF0 postblit 7FFF7D70BBD0==7FFF7D70BBF0 in someFunc In the last line pointers are not matching. I thought that postblit will do the thing but it is not the case. How to make 'ptr' to be null or '&this.x' all the time? D allows moving any struct instance without calling postblit, as long as the original is no longer used. The optimizer is likely seeing here that the memory can be copied without calling postblit, because nobody is using tmpA after the call. In general, you should NOT store an internal pointer in a struct, unless you allocate it on the heap. -Steve I need internal pointer because I want to implement vector(like in C++) with 'small vector optimization', when i have internal pointer it is very easy and functions like 'add' don't have additional checks. If storing internal pointers is forbidden do you know some way to implement 'small vector optimization' without additional checks in 'add' function? Hm... the only way to do it in D is to provide a function that checks whether the small vector optimization is in play, and return a pointer/slice to itself. With D it is possible to alias the getter function that provides the actual data to allow code to look nicer. For example (crude example): struct Vector(T) { bool svo; // small vector optimization union { T[4] local; T[] heap; } inout(T)[] get() inout { return svo ? local[], heap; } alias get this; ... // implement specialized append, concat operators, etc. } Now, you can use Vector as if it were an array, and it just works. -Steve
Re: What is the point of nothrow?
On Wednesday, June 13, 2018 10:56:41 wjoe via Digitalmars-d-learn wrote: > On Wednesday, 13 June 2018 at 03:14:33 UTC, Jonathan M Davis > > wrote: > > Most programs do not handle the case where they run out of > > memory and cannot continue at that point. For better or worse, > > D's GC was designed with that in mind, and it treats failed > > allocations as an Error. In the vast majority of cases, this is > > desirable behavior. In those cases when it isn't, alternate > > memory allocation schemes such as malloc can be used. But > > But manual memory management sucks and is a huge waste of > everyone's time and I was hoping to get the best from both worlds > > :) > : Well, I think that the reality of the matter is that the number of programs that even attempt to recover from not having enough memory is extremely small such that you're dealing with a very niche case if you're going to try it, and if the GC fails to allocate more memory for you, your options are typically pretty limited. So, even if the GC provided a way to allocate memory that returned null on failure instead of throwing an Error, I don't know that it would do you a lot of good, but regardless, the GC was not designed with that in mind, and even GC.malloc throws OutOfMemoryError on allocation failure rather than null. So, there isn't much choice on the matter. > > regardless of whether the decision to treat failed memory > > allocations as an Error was a good one or not, the fact remains > > that as soon as an Error is thrown, you lose the ability to > > deal with things cleanly, because full clean up is not done > > when an Error is thrown (and can't be due to things like how > > nothrow works). So, regardless of whether a failed memory > > allocation is a condition that can be recovered from in > > principle, the way that D handles GC allocations make it > > unrecoverable in practice - at least as far as GC-allocated > > memory is concerned. > > Did I get that right? > You say when an error is thrown destructors, scope statements, > etc. are not executed - if declared as nothrow because the > exception handler mechanism stuff is missing, is that correct? > And it does execute if not declared as nothrow but can't be > relied upon because some other nothrow functions could have > omitted some of those statements? Yes, and there's no guarantee that clean-up will occur even if nothing is nothrow. While the current implementation will do clean-up in those cases, it didn't used to, and Walter has repeatedly stated that it is not guaranteed to do so. Errors are _not_ intended to be caught and recovered from. They're essentially a segfault that prints a message and stack trace but which for some reason uses the exception throwing mechanism to get to the code that prints the message and exits the program. > So I shoot myself in the foot with nothrow and if I don't use it > I'm still in a world of hurt? > > I understand the idea that an Error is not supposed to be caught > but why would such a 'feature' be desirable? Where's the benefit > if nothing can be relied upon ? > > If all errors would be treated like an exception, the developer > could decide whether it is an error which needs to terminate > right away or be able to handle the issue and continue or > gracefully shutdown. The idea is that because your program is in an invalid state, attempting a graceful shutdown is unsafe. But regardless of whether you agree with that, the fact that nothrow doesn't do clean-up pretty much ensures that it isn't safe in the general case, and nothrow can't do clean-up without negating one of the main reasons that it exists in the first place - which is to improve performance by not emitting exception-handling code. > Could even set a break point or force a core > dump right there. The fact that Errors don't immediately kill the program and instead sort of unwind the stack is a definite problem for getting good debug information on crashes. I suspect that Walter doesn't quite understand the issues here, because whenever anyone raises issues related to stuff like this, he has a tendancy to basically tell people to rerun their program - which works fantastically in the world he typically programs in (compilers) but doesn't work very well with stuff like OSes or server programs where you frequently have no clue how to replicate the problem. My guess is that Errors work they do in part because he's not used to debugging situations where a coredump being created at the point of failure the first time it happens (rather than during attempts to reproduce the problem) is what you really need. I think that the reasons that this is not a bigger problem than it is stem primarily from the fact that Errors are going to be very rare in production code unless it wasn't properly tested. So, the problem shouldn't pop up often. However, when it does, having a coredump at the site of the failure would definitely be valuable. > If the exception would be ignored the prog
Re: Runtime introspection, or how to get class members at runtime Fin D
On Friday, 8 June 2018 at 08:21:39 UTC, evilrat wrote: On Friday, 8 June 2018 at 08:06:27 UTC, Arafel wrote: On Thursday, 7 June 2018 at 13:07:21 UTC, evilrat wrote: I don't think so. It clearly states that children must mixin too, which can mean it just grabs symbols in scope only, and base class has no way of knowing about its subclasses. It also has "agressive mode" that will make metadata for all public symbols(?) it can walk, this may or may not be helpful depending on your requirements. Yes, that's what I understood from looking at it, but perhaps I was just missing something. I wonder though how the "agressive mode" would work with separate compilation / dlopen'ed libraries. Perhaps I should give it a try and see what happens. Besides there is no way(not that I am aware of) to make self registering stuff happen, you still need to call it somewhere. The most transparent option is probably just doing a mixin in each module that performs registration of all module symbols in module ctor. The point is that there is absolute requirement to make explicit call for that, be it a module ctor mixin, class mixin or even user provided registration both at compile time or run time. But since it is MIT licensed you can probably use the code as the starting point and adjust to your own needs. BTW plug-ins is something that is right now possible on Linux(not sure about support on other *NIX systems), but in a very primitive form on Windows. This is related to DLL support issues(such as type information not being passed across process/DLL boundaries), these issues also may include runtime issues as well such as inability to delegate the GC, which will mean there will be 2(or more) concurrent running GC's. But again I am not aware of the current situation. Well, I'm already tightly coupled to linux, so this is not a big concern for me :-) I'll keep trying, as I said, my intention was to let plugin writers do it as easily as possible, but well, adding some kind of "register" function might be necessary in the end... A. Yep. Like I said probably the easiest to use way is to place single call in each module. And there probably no other solution, because modules creates sort of isolated graph via imports. And I am not aware of any way to get list of modules passed in with compiler invocation to perform some sort of centralized one-liner registration. But anyway look at this, might give some tips on how it can be done mixin https://github.com/Circular-Studios/Dash/blob/b7d589ad4ca8993445c136b6a4ae170932bb7962/source/dash/components/component.d#L208 (note that it uses static this() - module constructor. I think this behavior was changed around 2015-2016 and now it will cause cyclic dependency errors when modules with ctors import each other) usage https://github.com/Circular-Studios/Dash/blob/b7d589ad4ca8993445c136b6a4ae170932bb7962/source/dash/components/lights.d#L12 Thanks very much for these links! I'm currently also trying to get a crack at runtime introspection for enabling richer serialization capabilities. It is nice to have compile time code generation, but it really sucks when dealing with object hierarchies and API interfaces. I'm doing kind of the same thing as witchcraft with explicit mixins (putting a "mixin reflect" into every stuff I want to reflect on.) But I'd like to have selective reflection/introspection, with a C#-esque flavor of having a "centralised repository" of reflected stuff. Also I need to inject static this(). A serious drawback. On that note, you can pass: --DRT-oncycle=ignore to your compiled app to instruct the runtime to ignore cycle warnings. linux ex.: "./app --DRT-oncycle=ignore" It is ugly as hell to disable this check, but I would accept it gladly if this would be the only impediment of getting runtime reflection. Sadly it is not, and I don't want to ramble right now :)
Re: Class qualifier vs struct qualifier
On Wednesday, June 13, 2018 07:35:25 RazvanN via Digitalmars-d-learn wrote: > Hello, > > I'm having a hard time understanding whether this inconsistency > is a bug or intended behavior: > > immutable class Foo {} > immutable struct Bar {} > > void main() > { > import std.stdio : writeln; > Foo a; > Bar b; > > writeln("typeof(a): ", typeof(a).stringof); > writeln("typeof(b): ", typeof(b).stringof); > } > > prints: > > typeof(Foo): Foo > typeof(Bar): immutable(Bar) > > > It seems like the class storage class is not taken into account > which leads to some awkward situations like: > > immutable class Foo > { > this() {} > } > > void main() > { > Foo a = new Foo(); // error: immutable method `this` is not > callable using a > // mutable object > } > > To make it work I have to add immutable to both sides of the > expression : immutable Foo a = new immutable Foo(); this is a > wonder of redundancy. I already declared the class as immutable > so it shouldn't be possible to have mutable instances of it (and > it isn't), however I am forced to write the immutable twice even > though it is pretty obvious that the class cannot be mutated. Honestly, from what I understand of how this works, what I find weird is the struct case. immutable on classes does _not_ make the class itself immutable. It just makes all of its members immutable - hence the error about trying to allocate new Foo instead of new immutable Foo. So, that is exactly what I would expect. And honestly, being able to write Foo and have it imply immutable Foo would get _really_ confusing when reading and debugging code. What's bizarre is that marking the struct with immutable would affect anything other than its members. Bar b; should not claim that typeof(b) is immutable(Bar). b was not marked as immutable. It was listed as Bar, not immutable Bar. So, b shouldn't be immutable. - Jonathan M Davis
Re: Class qualifier vs struct qualifier
On Wednesday, June 13, 2018 14:33:48 Jonathan M Davis via Digitalmars-d- learn wrote: > On Wednesday, June 13, 2018 07:35:25 RazvanN via Digitalmars-d-learn wrote: > > Hello, > > > > I'm having a hard time understanding whether this inconsistency > > is a bug or intended behavior: > > > > immutable class Foo {} > > immutable struct Bar {} > > > > void main() > > { > > > > import std.stdio : writeln; > > Foo a; > > Bar b; > > > > writeln("typeof(a): ", typeof(a).stringof); > > writeln("typeof(b): ", typeof(b).stringof); > > > > } > > > > prints: > > > > typeof(Foo): Foo > > typeof(Bar): immutable(Bar) > > > > > > It seems like the class storage class is not taken into account > > which leads to some awkward situations like: > > > > immutable class Foo > > { > > > > this() {} > > > > } > > > > void main() > > { > > > > Foo a = new Foo(); // error: immutable method `this` is not > > > > callable using a > > > > // mutable object > > > > } > > > > To make it work I have to add immutable to both sides of the > > expression : immutable Foo a = new immutable Foo(); this is a > > wonder of redundancy. I already declared the class as immutable > > so it shouldn't be possible to have mutable instances of it (and > > it isn't), however I am forced to write the immutable twice even > > though it is pretty obvious that the class cannot be mutated. > > Honestly, from what I understand of how this works, what I find weird is > the struct case. immutable on classes does _not_ make the class itself > immutable. It just makes all of its members immutable - hence the error > about trying to allocate new Foo instead of new immutable Foo. So, that > is exactly what I would expect. And honestly, being able to write Foo and > have it imply immutable Foo would get _really_ confusing when reading and > debugging code. > > What's bizarre is that marking the struct with immutable would affect > anything other than its members. > > Bar b; > > should not claim that typeof(b) is immutable(Bar). b was not marked as > immutable. It was listed as Bar, not immutable Bar. So, b shouldn't be > immutable. https://issues.dlang.org/show_bug.cgi?id=18977 - Jonathan M Davis
Which character set does D use?
Does D use ASCII or UNICODE? It seems to use ASCII since it causes error whenever I use a non-ASCII character.
Re: Which character set does D use?
On Wednesday, 13 June 2018 at 23:34:02 UTC, Murilo wrote: Does D use ASCII or UNICODE? It seems to use ASCII since it causes error whenever I use a non-ASCII character. Your system might be misconfigured. D can use UTF-8 (Unicode) too. See https://dlang.org/spec/lex.html#source_text
InputRange help: (1) repeated dtor calls and (2) managing resources needing free()
Hi all, I now really appreciate the power Ranges provide and am an avid consumer, but am only slowly becoming accustomed to implementing my own. In the present problem, I am writing a binding to a C library (htslib) that provides many functions related to high-throughput sequencing files. One of these functions is for rapid indexed lookup into multi-GB files. The library provides a handle to an iterator which must be supplied to a "get next matching row" type function, which overall seems perfect for implementation as a range. You can see my naive implementation here: https://github.com/blachlylab/dhtslib/blob/master/source/dhtslib/tabix.d Note that TabixIndexedFile::region returns an InputRange; in the original implementation, this Range preloaded the first record (the ctor called popFirst()), but ultimately I realized this was not workable because copies of the object would always be non-empty. In some ways, this problem is generalizable to all InputRanges that represent a file or record stream. My problems now are at least twofold. 1. If I use the range, the destructor seems to be called many, many times. This is directly related to problem 2, below, but I would be interested to understand why this is happening generally. For example, see: https://github.com/blachlylab/dhtslib/blob/master/test/tabix_gffreader.d Here, when I create the range but do not consume it, the ctor and dtor are called once each, as expected. However, if I foreach(line; r) { } the destructor is called twice. If I reason through this, it is because use of the range created a copy to consume. (?) However, if instead, I writeln( r ), the destructor is called *five* times. I cannot understand the reason for this, unless it is black magic required by writeln(). I assume the (apparent) lack of parity between ctor and dtor is because the "default postblit" (which I figured out for a struct means an empty `this(this)` ctor) is called when a copy is made. My understanding is that I cannot disable the default postblit and still act as a range, correct? Should I be overloading this? 2. Directly related to the above, I need, when the range is consumed, to free() the underlying library's iterator handle. Naively, I had the destructor do this, but obviously with multiple calls to ~this I end up with an error free()'ing a pointer that is no longer alloc'd. What is the correct way to handle this situation in D? Other Range and destructor advice generally (e.g., "You should totally change your design or approach to X instead") is always welcomed. James
Re: Docs for subpackages?
On Wednesday, 13 June 2018 at 14:56:10 UTC, 9il wrote: Hi, I am trying to build a large project that is split into dozen of sub-packages. How I can do it using dub without writing my own doc scripts? --combined does not help here. Best regards, Ilya UPDATE: --combined works, but DDOX fails std.json.JSONException@std/json.d(1394): Got JSON of type undefined, expected string. 4 ddox0x000107c667fa const pure @safe void vibe.data.json.Json.checkType!(immutable(char)[]).checkType(immutable(char)[]) + 278 5 ddox0x000107c666cb inout @property @trusted inout(immutable(char)[]) vibe.data.json.Json.get!(immutable(char)[]).get() + 31 6 ddox0x000107dba2bc ddox.entities.Declaration ddox.parsers.jsonparser.Parser.parseDecl(vibe.data.json.Json, ddox.entities.Entity) + 72 7 ddox0x000107dba106 int ddox.parsers.jsonparser.Parser.parseDeclList(vibe.data.json.Json, ddox.entities.Entity).__foreachbody3(ref vibe.data.json.Json) + 90 8 ddox0x000107fe1fd7 int vibe.data.json.Json.opApply(scope int delegate(ref vibe.data.json.Json)) + 159 9 ddox0x000107dba09a ddox.entities.Declaration[] ddox.parsers.jsonparser.Parser.parseDeclList(vibe.data.json.Json, ddox.entities.Entity) + 78 10 ddox0x000107dbb024 ddox.entities.CompositeTypeDeclaration ddox.parsers.jsonparser.Parser.parseCompositeDecl(vibe.data.json.Json, ddox.entities.Entity) + 712 11 ddox0x000107dba520 ddox.entities.Declaration ddox.parsers.jsonparser.Parser.parseDecl(vibe.data.json.Json, ddox.entities.Entity) + 684 12 ddox0x000107dba106 int ddox.parsers.jsonparser.Parser.parseDeclList(vibe.data.json.Json, ddox.entities.Entity).__foreachbody3(ref vibe.data.json.Json) + 90 13 ddox0x000107fe1fd7 int vibe.data.json.Json.opApply(scope int delegate(ref vibe.data.json.Json)) + 159 14 ddox0x000107dba09a ddox.entities.Declaration[] ddox.parsers.jsonparser.Parser.parseDeclList(vibe.data.json.Json, ddox.entities.Entity) + 78 15 ddox0x000107db8ef3 void ddox.parsers.jsonparser.Parser.parseModuleDecls(vibe.data.json.Json, ddox.entities.Package) + 583 16 ddox0x000107db8c9f int ddox.parsers.jsonparser.parseJsonDocs(vibe.data.json.Json, ddox.entities.Package).__foreachbody3(ref vibe.data.json.Json) + 91 17 ddox0x000107fe1fd7 int vibe.data.json.Json.opApply(scope int delegate(ref vibe.data.json.Json)) + 159 18 ddox0x000107db8c2d ddox.entities.Package ddox.parsers.jsonparser.parseJsonDocs(vibe.data.json.Json, ddox.entities.Package) + 89 19 ddox0x000107d9d53c ddox.entities.Package ddox.main.parseDocFile(immutable(char)[], ddox.settings.DdoxSettings) + 168 20 ddox0x000107d9c1ad int ddox.main.setupGeneratorInput(ref immutable(char)[][], out ddox.settings.GeneratorSettings, out ddox.entities.Package) + 777 21 ddox0x000107d9bab6 int ddox.main.cmdGenerateHtml(immutable(char)[][]) + 42 22 ddox0x000107d9b945 int ddox.main.ddoxMain(immutable(char)[][]) + 201 23 ddox0x000107c617bf _Dmain + 31 24 ddox0x00010800d037 void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll().__lambda1() + 39 25 ddox0x00010800cec7 void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) + 31 26 ddox0x00010800cfa2 void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() + 138 27 ddox0x00010800cec7 void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) + 31 28 ddox0x00010800ce35 _d_run_main + 485 29 ddox0x000107c617e9 main + 33 30 libdyld.dylib 0x7fff7d479014 start + 0 31 ??? 0x0004 0x0 + 4
Re: Passing struct to function
On Wednesday, 13 June 2018 at 17:37:44 UTC, Steven Schveighoffer wrote: Hm... the only way to do it in D is to provide a function that checks whether the small vector optimization is in play, and return a pointer/slice to itself. With D it is possible to alias the getter function that provides the actual data to allow code to look nicer. For example (crude example): struct Vector(T) { bool svo; // small vector optimization union { T[4] local; T[] heap; } inout(T)[] get() inout { return svo ? local[], heap; } alias get this; ... // implement specialized append, concat operators, etc. } Now, you can use Vector as if it were an array, and it just works. -Steve Thanks for an idea, I will try it.