Re: core.sys.posix.unistd link error
Didn't catch. How can I use it at runtime? I can not link to actually C function? On Saturday, 21 September 2013 at 19:40:48 UTC, Jonathan M Davis wrote: On Saturday, September 21, 2013 20:30:00 Ruslan Mullakhmetov wrote: i use pipe() syscall from my program. when i compile it I got the following msg: Error: pipe cannot be interpreted at compile time, because it has no available source code how can i fix it? dmd 2.063.2, Mac OS X It sounds like you're trying to use pipe at compile time, and as the error says, you can't use it at compile time, because no source code for it is available. The same goes for all C functions. They can only be used at runtime. - Jonathan M Davis
Re: core.sys.posix.unistd link error
I found where the problem is. I used a system call (external C function) in class ctor. then I declared global variable of this class and INITIALZIED that variable inplace. If i move initalization in module static this() everything compiles. the code is: incorrect version: http://dpaste.com/hold/1391530/ correct: http://dpaste.com/hold/1391523/ But now i need to sort out what the difference between // global scope int a = 10; and int a; static this() { a = 10; } I appreciate if somebody give a link or chapter number where to read.
Cannot use locat x as parameter to non-global template y
God, I hate these errors. Tried updating dmd head, and these started popping up. Now I have to move all templates out...
Re: Cannot use locat x as parameter to non-global template y
simendsjo: God, I hate these errors. Tried updating dmd head, and these started popping up. Now I have to move all templates out... Can you show a small example of code that gives that error? Bye, bearophile
Re: Cannot use locat x as parameter to non-global template y
On Sunday, 22 September 2013 at 12:26:03 UTC, bearophile wrote: simendsjo: God, I hate these errors. Tried updating dmd head, and these started popping up. Now I have to move all templates out... Can you show a small example of code that gives that error? Bye, bearophile Nope. I cannot get dustmite to work: https://github.com/CyberShadow/DustMite/issues/16
Re: Cannot use locat x as parameter to non-global template y
On Sunday, 22 September 2013 at 12:26:03 UTC, bearophile wrote: simendsjo: God, I hate these errors. Tried updating dmd head, and these started popping up. Now I have to move all templates out... Can you show a small example of code that gives that error? Bye, bearophile dustmite for the win! template A(T...) { template B(alias T) { } } void main() { void fv() {} alias A!(fv) F; F.B!F; } dmd -unittest t.d t.d(8): Error: template instance B!(A!(fv)) cannot use local 'A!(fv)' as parameter to non-global template B(alias T)
Regression or bugfix?
In 2.063.2, (T!int).stringof == T!(int). In current head, it's T!int. Even (T!(int)).stringof == T!int. So is this a regression bug or a bugfix?
Re: Cannot use locat x as parameter to non-global template y
On Sunday, 22 September 2013 at 13:36:48 UTC, simendsjo wrote: On Sunday, 22 September 2013 at 12:26:03 UTC, bearophile wrote: simendsjo: God, I hate these errors. Tried updating dmd head, and these started popping up. Now I have to move all templates out... Can you show a small example of code that gives that error? Bye, bearophile dustmite for the win! template A(T...) { template B(alias T) { } } void main() { void fv() {} alias A!(fv) F; F.B!F; } dmd -unittest t.d t.d(8): Error: template instance B!(A!(fv)) cannot use local 'A!(fv)' as parameter to non-global template B(alias T) Added a ticket too: http://d.puremagic.com/issues/show_bug.cgi?id=11098 Probably a dup of many of the other local aliasing tickets though..
join of range of ranges?
In some cases I'd like to join a range of ranges in a single array/string (I know here the inner map could be replaced by something better, this code is just an example): import std.algorithm: map; import std.array: join, array; void main() { auto r1 = [1, 2] .map!(x = [1, 2].map!(y = '*').array) .join(_); auto r2 = [1, 2] .map!(x = [1, 2].map!(y = '*')) .join(_); } The code works only if I add an 'array' inside, to turn it into a range of arrays. Do you think it's right to ask as enhancement for std.array.join to work with a range of ranges too, as in the r2 case? Bye, bearophile
Re: Regression or bugfix?
On Sunday, 22 September 2013 at 13:50:00 UTC, simendsjo wrote: In 2.063.2, (T!int).stringof == T!(int). In current head, it's T!int. Even (T!(int)).stringof == T!int. So is this a regression bug or a bugfix? Added a ticket so it doesn't get lost: http://d.puremagic.com/issues/show_bug.cgi?id=11100
Re: join of range of ranges?
On Sunday, 22 September 2013 at 14:26:14 UTC, bearophile wrote: In some cases I'd like to join a range of ranges in a single array/string (I know here the inner map could be replaced by something better, this code is just an example): std.algorithm.joiner, or am I missing something? David
const and immutable members
In this thread (http://forum.dlang.org/thread/uvhwkgljavskqfueq...@forum.dlang.org) I asked this: 3) Also, is storing immutable(STUFF) in a struct in the general case (as opposed to just this one) useful or silly? Johnathan M Davis replied: As soon as you have a const or immutable member in a struct, you can't ever assign anything to it, even if all of its other members are mutable (you could assign the individual, mutable members but not the whole struct). That means stuff like if the struct is ever default-initialized, you can't even give it another value, which tends to mean that you can't use such a struct in places like arrays. All in all, I think that it's pretty much always a bad idea to have a struct with const or immutable members. It's just begging for problems. Tail-const or tail-immutable is fine, because the members themselves aren't const or immutable (just what they refer to), but having them be directly const or immutable is a bad idea IMHO. I don't really understand the _tail-const_, _tail-immutable_ argument. Why is _tail-const_ fine but not _const_ when there is transitivity anyway? I think there are only a handful of places you consider using const/immutable: - Global variables - Local variables - Member variables - Function signatures Are there any missing? If right out of the gate the feeling is member variables should not be const or immutable, doesn't that greatly reduce the value of the mutability specificiers? Members are used to hold onto the data for the lifecycle of the object and if those should not make claims or guarantees on mutability then that seems a shame. What do others think? Are there cases where const/immutable members are being used in a good way? In that thread I gave a motivation for it (I used emacs and the formatting turned out awful - so sorry about that). But not sure if my logic holds water. Thanks Dan
Re: cast(immutable) vs extra variable
On 09/19/2013 03:07 PM, Daniel Davidson wrote: Here is a setup: Data is coming in - say over the wire or from a database. It is very rich data with nestings of primitives, lists and string keyed associative arrays, recursively - think nested json. Once a data object is read in it is passed off to classes that use the data in read-only fashion. And there are two types of read-only data: const: A promise to not mutate immutable: A requirement that nobody mutates either. So, for example, assume the root of the rich data is a Portfolio instance. All members of Portfolio recursively are public since it is really plain old data from one perspective and this makes using vibe json serialization simple. Assume that a user of Portfolio data is an Analyzer. This analyzer will need to do lots of complex operations with the portfolio that it uses in readonly fashion. Yes, that sounds like immutable(Portfolio), as the Analyzer would not be happy if the data could mutate. It may have many mutable members for intermediate calculations. Here is a mockup http://pastebin.com/nBLFDgv6 which is making use of immutable(Portfolio) to ensure that (a) the analyzer does not modify the data and (b) no other code can modify the data. To achieve this there needs to be a point in time where the modifiable Portfolio is done being read and made immutable. At this point it is cast to immutable and henceforth only accessed that way. I have added a couple of comments to you program: import std.stdio; struct Portfolio { double[string] data; // ... } struct HedgeRecommendation { string recommendation; this(int) { recommendation = Sell, the market is rigged; } } struct Analyzer { // [Ali] Since you are worried about cost of copying, why not make this a // pointer as well? immutable(Portfolio)* portfolio; this(ref immutable(Portfolio) portfolio) { // [Ali] Otherwise, this assignment would copy as well. this.portfolio = portfolio; } HedgeRecommendation createHedge() { auto result = HedgeRecommendation(1); //... return result; } } // [Ali] If possible, make this function pure so that its return value can // automatically be casted to immutable. Portfolio readPortfolio(string id) pure { // read portfolio from database return Portfolio([ IBM : 100.0, SPY : 300.0 ]); } HedgeRecommendation getHedgeRecommendation(string portfolioId) { // [Ali] No explicit cast needed because of that 'pure'. immutable(Portfolio) portfolio = readPortfolio(portfolioId); auto analyzer = Analyzer(portfolio); return analyzer.createHedge(); } void main() { writeln(getHedgeRecommendation(1234)); } Given this setup - what do you see as the trade-offs? What can not be done or will be challenging in face of refactor? What are some better alternatives/recommendations? I am a fan of D but my struggles with const/immutable transitivity feel endless and are wearing on me. I feel like having an ability to say something will not change and not using that ability is like being teased. You are not alone. I tried to answer some of these questions in my DConf 2013 talk. I think I have only scratched the surface: http://dconf.org/talks/cehreli.html Ali
[Question] About mixin, template and alias
/// fire.d import std.stdio; alias void delegate() EventHandler; class Event(T) { private T[] _events; public void opOpAssign(string op)(T param) if (op == ~) { writeln(param.funcptr); _events ~= param; } public void opCall(ParamType ...)(ParamType params) { emit(params); } protected void emit(ParamType ...)(ParamType params) { foreach (event; _events) event(params); } } mixin template AddEvent(DelegateType, string member) { auto eventObserver = new Event!DelegateType(); mixin(alias eventObserver ~ member ~ ;); } class Fire { public mixin AddEvent!(EventHandler, click); } /// water.d import std.stdio; import fire; class Water : Fire { } void main() { auto fire = new Fire(); auto water = new Water(); water.click ~= () { writeln(Water!); }; fire.click ~= () { writeln(Fire!); }; fire.click(); } Output: Water! Fire! Someone can explain me a behaviour of above code? Why not Fire! only?
Re: [OT] Pathfinding algorithm
On Saturday, 21 September 2013 at 15:49:00 UTC, rasmus svensson wrote: Assuming the shortest path from from all nodes to every other node is already pre-computed: What is a fast algorithm to update all paths, if one node is marked as inpassible. Any good 3rd party library or research paper out there? A short note on worst case complexity. In a star graph, if you remove the central vertex, *all* paths between pairs of other vertices are affected (they become pairwise unreachable). So, if there is a way to do it in less than V^2, it will at least have to store paths in some sophisticated way, better than just a VxV matrix with one element for each path. Ivan Kazmenko.
Re: core.sys.posix.unistd link error
On Sunday, September 22, 2013 13:52:54 Ruslan Mullakhmetov wrote: But now i need to sort out what the difference between // global scope int a = 10; That directly initializes the variable at compile time, meaning that whatever is used to initialize the variable must be callable at compile time. And the value must be able to be set at compile time and then be carried over to runtime. That will work with int, but it does not work with most stuff that's on the heap (like classes or AAs) - arrays would be the major exception to that, since they can be set at compile time (and I believe that it was recently changed so that immutable classes could be set at compile time, but not const or mutable ones - implementing that is rather complicated, and it may or may not ever happen). Over time, what you can do at compile time with CTFE (Compile Time Function Evaluation) has improved, but there are still restrictions, and some things will never be possible (e.g. I/O or calling C functions). and int a; static this() { a = 10; } That does not set the variable at compile time. Rather, the static constructor sets it at runtime. So, this has none of the restrictions that directly initializing a module or static variable does. However, it does have the downside that two modules that have static constructors can't import each other (either directly or indirectly), because then the runtime wouldn't know which order to run them in. If you do that, you'll get an exception at runtime complaining about a circular import (which sucks, but unfortunately, the circular import can't always be detected at compile time - thanks in part to .di files - so runtime detection is the best that can be done). So, while static constructors can be really nice, you do have to avoid having modules that use them import each other, which means either being careful about how your modules import each other or avoiding static constructors. Which is easier depends on your code.
Re: core.sys.posix.unistd link error
I would be curious to see why you believe them to be the same. Cause i'm a C++ programmer and there is no such thing as module and module initializer, in fact object file initialization consist of initialization of all its static variables somewhen before the first call of a function in that object file (if any). On Sunday, 22 September 2013 at 19:50:14 UTC, Dmitry Olshansky wrote: 22-Sep-2013 15:52, Ruslan Mullakhmetov пишет: I found where the problem is. I used a system call (external C function) in class ctor. then I declared global variable of this class and INITIALZIED that variable inplace. If i move initalization in module static this() everything compiles. the code is: incorrect version: http://dpaste.com/hold/1391530/ correct: http://dpaste.com/hold/1391523/ But now i need to sort out what the difference between // global scope int a = 10; This just puts calculated value 10 into TLS data section as initializer for a. and int a; static this() { a = 10; } This defines a global with 0 initializer. Then static this is a function that is executed for each D thread on creation, following the module dependency chain (i.e. if there is static this in imported module it should be run first). I would be curious to see why you believe them to be the same. I appreciate if somebody give a link or chapter number where to read.
Re: const and immutable members
On Sunday, September 22, 2013 18:15:08 Daniel Davidson wrote: In this thread (http://forum.dlang.org/thread/uvhwkgljavskqfueq...@forum.dlang.org) I asked this: 3) Also, is storing immutable(STUFF) in a struct in the general case (as opposed to just this one) useful or silly? Johnathan M Davis replied: As soon as you have a const or immutable member in a struct, you can't ever assign anything to it, even if all of its other members are mutable (you could assign the individual, mutable members but not the whole struct). That means stuff like if the struct is ever default-initialized, you can't even give it another value, which tends to mean that you can't use such a struct in places like arrays. All in all, I think that it's pretty much always a bad idea to have a struct with const or immutable members. It's just begging for problems. Tail-const or tail-immutable is fine, because the members themselves aren't const or immutable (just what they refer to), but having them be directly const or immutable is a bad idea IMHO. I don't really understand the _tail-const_, _tail-immutable_ argument. Why is _tail-const_ fine but not _const_ when there is transitivity anyway? If you have struct S { immutable int[] arr; } then arr can never be assigned to, so a variable of type S can never be assigned to. But if you have struct S { immutable(int)[] arr; } then arr can be reassigned as much as you'd like, so S can be assigned to. In both cases, the elements of the array are immutable, so it can freely be a slice of another array and not care or affect that other array, but the array variable itself - which only exists local to the struct - is not restricted in being assigned to. So, you get the immutability of the data without restricting the struct. All making arr itself immutable does (rather than tail-immutable) is make it so that you can't reassign arr, which can be useful sometimes, but in the case of a struct, it makes it so that the whole struct can't be reassigned, so it's pretty much never a good idea IMHO to have a struct with const or immutable members - but having them be tail-const or tail-immutable still makes it so that what they refer to gets all of the benefits of const or immutable without restricting the struct. If you're dealing with a class, then the situation is a bit different, because the class is always on the heap, and you don't normally assign to classes. You reassign the reference that refers to them or you assign to their member variables, but you don't assign to the block of data that is the class itself like you would with a struct. So, making a class' member variable const or immutable does not restrict the class, which means that if you want to make it so that the member variable can't be reassigned, making it fully const or fully immutable is fine. I think there are only a handful of places you consider using const/immutable: - Global variables - Local variables - Member variables - Function signatures Are there any missing? You can use const and immutable anywhere that you declare a variable or member function. If right out of the gate the feeling is member variables should not be const or immutable, doesn't that greatly reduce the value of the mutability specificiers? Members are used to hold onto the data for the lifecycle of the object and if those should not make claims or guarantees on mutability then that seems a shame. It's only a problem to make members fully const or immutable with structs, because then you can't reassign the struct, which does nasty things like make it so that you can't put them in arrays unless you want all the elements of the array to have the init value for that struct or you want to append each element individually (which won't work with static arrays). Also, the benefits of sharing data are only gained when that data is on the heap, in which case you can just make the data const or immutable without making the member variable in the struct const or immutable - you make it tail-const or tail-immutable rather than const or immutable. If the data were directly in the struct (i.e. the member variable is a value type), then the only way to share it would be via a pointer or via ref. ref doesn't really matter, since you can make that const, and it only refers to the data until the function call has completed. And pointers don't matter, because you can't actually rely on a pointer to a struct's member variable staying valid longer than ref would have anyway, because structs can be moved rather than copied. So, sharing via the heap is the only viable way, and if you do that, you can use tail-const or tail-immutable for all of the same benefits that making the member variable fully const or immutable would have given you (since you're sharing the data, not the variable). And again, the problems with making a member variable fully const or
Re: core.sys.posix.unistd link error
Thanks. I suspected it but i wanted a formal reference. the logic, though little bit cleared by you is quite obvious. But don't waste time, if you can not tell from a scratch that this is clause x.y.z of the Standard, sorry, Book. On Sunday, 22 September 2013 at 19:56:36 UTC, Jonathan M Davis wrote: On Sunday, September 22, 2013 13:52:54 Ruslan Mullakhmetov wrote: But now i need to sort out what the difference between // global scope int a = 10; That directly initializes the variable at compile time, meaning that whatever is used to initialize the variable must be callable at compile time. And the value must be able to be set at compile time and then be carried over to runtime. That will work with int, but it does not work with most stuff that's on the heap (like classes or AAs) - arrays would be the major exception to that, since they can be set at compile time (and I believe that it was recently changed so that immutable classes could be set at compile time, but not const or mutable ones - implementing that is rather complicated, and it may or may not ever happen). Over time, what you can do at compile time with CTFE (Compile Time Function Evaluation) has improved, but there are still restrictions, and some things will never be possible (e.g. I/O or calling C functions). and int a; static this() { a = 10; } That does not set the variable at compile time. Rather, the static constructor sets it at runtime. So, this has none of the restrictions that directly initializing a module or static variable does. However, it does have the downside that two modules that have static constructors can't import each other (either directly or indirectly), because then the runtime wouldn't know which order to run them in. If you do that, you'll get an exception at runtime complaining about a circular import (which sucks, but unfortunately, the circular import can't always be detected at compile time - thanks in part to .di files - so runtime detection is the best that can be done). So, while static constructors can be really nice, you do have to avoid having modules that use them import each other, which means either being careful about how your modules import each other or avoiding static constructors. Which is easier depends on your code.
Re: join of range of ranges?
Peter Alexander: The problem is that you are trying to map a range of range of chars with a range of dchars. auto r2 = [1, 2] .map!(x = [1, 2].map!(y = cast(dchar)'*')) .join(_); This works. I see, thank you. When I ask a question it seems my brain switches off a bit :-) I really wish character literals in D where always dchar. This is supported: void main() { auto s1 = hellow; auto s2 = hellod; } So, what about adding support for this? void main() { auto c1 = 'X'w; auto c2 = 'X'd; static assert(is(typeof(c1) == wchar)); static assert(is(typeof(c2) == dchar)); } Bye, bearophile
Re: const and immutable members
On Sunday, 22 September 2013 at 16:15:09 UTC, Daniel Davidson wrote: [...] 3) Also, is storing immutable(STUFF) in a struct in the general case (as opposed to just this one) useful or silly? [...] I don't really understand the _tail-const_, _tail-immutable_ argument. Why is _tail-const_ fine but not _const_ when there is transitivity anyway? [...] If right out of the gate the feeling is member variables should not be const or immutable, doesn't that greatly reduce the value of the mutability specificiers? Members are used to hold onto the data for the lifecycle of the object and if those should not make claims or guarantees on mutability then that seems a shame. By marking the tail of the member const -- e.g. const(int)[] --, you're committing to not altering the refered-to data. This means, the user of your struct can put in mutable and immutable data. When you mark it full-const -- const(int[]) -- you're taking away from the user the ability to make it refer to some other data. In particular, setting a variable of your struct type to a new value requires mutable members. There may be special cases where that extra restriction is desired, but I can't think of one. Unless you're in such a special case, it just hurts the user for no reason. And when the user needs a const object, they can do that on their own: struct S {int x;} const s = S(42); static assert(is(typeof(s.x) == const));
Re: join of range of ranges?
On Sunday, 22 September 2013 at 20:27:01 UTC, bearophile wrote: Peter Alexander: The problem is that you are trying to map a range of range of chars with a range of dchars. auto r2 = [1, 2] .map!(x = [1, 2].map!(y = cast(dchar)'*')) .join(_); This works. I see, thank you. When I ask a question it seems my brain switches off a bit :-) I really wish character literals in D where always dchar. This is supported: void main() { auto s1 = hellow; auto s2 = hellod; } So, what about adding support for this? void main() { auto c1 = 'X'w; auto c2 = 'X'd; static assert(is(typeof(c1) == wchar)); static assert(is(typeof(c2) == dchar)); } Bye, bearophile Even helloc is supported actually :) It can make a difference if you *don't* want your string implicitly promoted on declaration. EG: dstring ds1 = hello; //Fine dstring ds2 = helloc; //Nope. As for allowing 'X'w, I think the rationale is that a cast will get you the same result (not so with string literals).
Re: join of range of ranges?
On Sunday, 22 September 2013 at 18:13:39 UTC, Peter Alexander wrote: On Sunday, 22 September 2013 at 14:26:14 UTC, bearophile wrote: auto r2 = [1, 2] .map!(x = [1, 2].map!(y = '*')) .join(_); The problem is that you are trying to map a range of range of chars with a range of dchars. This could also be solved by having join return an array of the CommonType of the elements of both ranges.
Re: [Question] About mixin, template and alias
On Sunday, 22 September 2013 at 18:31:20 UTC, Michael wrote: /// fire.d import std.stdio; alias void delegate() EventHandler; class Event(T) { private T[] _events; public void opOpAssign(string op)(T param) if (op == ~) { writeln(param.funcptr); _events ~= param; } public void opCall(ParamType ...)(ParamType params) { emit(params); } protected void emit(ParamType ...)(ParamType params) { foreach (event; _events) event(params); } } mixin template AddEvent(DelegateType, string member) { auto eventObserver = new Event!DelegateType(); mixin(alias eventObserver ~ member ~ ;); } class Fire { public mixin AddEvent!(EventHandler, click); } /// water.d import std.stdio; import fire; class Water : Fire { } void main() { auto fire = new Fire(); auto water = new Water(); water.click ~= () { writeln(Water!); }; fire.click ~= () { writeln(Fire!); }; fire.click(); } Output: Water! Fire! Someone can explain me a behaviour of above code? Why not Fire! only? This: // auto eventObserver = new Event!DelegateType(); // Does not do what you think it does: It *statically* initializes eventObserver to the *single* new Event!DelegateType();. SO basically, all your instances are sharing the same Event. I'm surprised this compiles at all, what with Fire.init depending on a run-time call, but apparently, dmd is smart enough to do the allocation at compile time.
Re: [Question] About mixin, template and alias
This: // auto eventObserver = new Event!DelegateType(); // Does not do what you think it does: It *statically* initializes eventObserver to the *single* new Event!DelegateType();. SO basically, all your instances are sharing the same Event. I'm surprised this compiles at all, what with Fire.init depending on a run-time call, but apparently, dmd is smart enough to do the allocation at compile time. Why like static?
Re: join of range of ranges?
monarch_dodra: As for allowing 'X'w, I think the rationale is that a cast will get you the same result (not so with string literals). OK. I have desired those char suffixes for years, so now I have written an ER: http://d.puremagic.com/issues/show_bug.cgi?id=11103 Bye, bearophile
C++ library says to delete data that it allocates
I'm trying to use a C++ library that allocates data and returns a pointer to it. It tells me that I should delete the data when I'm through with it. Can I do this from within D? Or do I need to write some C++ code to manage the delete, and pass the pointer on to it? -- Charles Hixson
Re: C++ library says to delete data that it allocates
On Sunday, 22 September 2013 at 23:09:52 UTC, Charles Hixson wrote: I'm trying to use a C++ library that allocates data and returns a pointer to it. It tells me that I should delete the data when I'm through with it. Can I do this from within D? Or do I need to write some C++ code to manage the delete, and pass the pointer on to it? You can't use delete straight from D, so I'd write the delete in C++ and pass the pointer back to C++, like you say.
Re: C++ library says to delete data that it allocates
On Monday, September 23, 2013 01:12:55 w0rp wrote: On Sunday, 22 September 2013 at 23:09:52 UTC, Charles Hixson wrote: I'm trying to use a C++ library that allocates data and returns a pointer to it. It tells me that I should delete the data when I'm through with it. Can I do this from within D? Or do I need to write some C++ code to manage the delete, and pass the pointer on to it? You can't use delete straight from D, so I'd write the delete in C++ and pass the pointer back to C++, like you say. Yeah. Memory needs to be freed by the same allocator that allocated it, as that's the allocator that manages it (e.g. if C's malloc allocated the memory, then C's free must free it, or if C++'s new allocated it, then C++'s delete must free it). So, if C++ code allocated something, it's going to have to be C++ code which frees it (though that could be managed by some kind of smart pointer in D which called a C++ function to free the memory when the smart pointer determined that the memory needed to be freed). - Jonathan M Davis
Re: const and immutable members
On Sunday, 22 September 2013 at 20:17:03 UTC, Jonathan M Davis wrote: If you have struct S { immutable int[] arr; } then arr can never be assigned to, so a variable of type S can never be assigned to. But if you have Yes - it (arr) can never be assigned to. That is the idea. It has already been assigned to when the data was read in, prior to construction of S. arr is initialized in the ctor of S. struct S { immutable(int)[] arr; } then arr can be reassigned as much as you'd like, so S can be assigned to. I don't imagine wanting that in this case. I want to ensure the array passed at construction in is the same array being used in read-only fashion throughout the lifecycle of S. That is my intention behind using immutable. I'm saying I'll not change it and no one else can, other wise functions of S that might have made assumptions about arr could be invalidated. In both cases, the elements of the array are immutable, so it can freely be a slice of another array and not care or affect that other array, but the array variable itself - which only exists local to the struct - is not restricted in being assigned to. So, you get the immutability of the data without restricting the struct. All making arr itself immutable does (rather than tail-immutable) is make it so that you can't reassign arr, It also keeps the contents of arr from growing and surprising S . You could try to prevent with private, but still if it is a large module why not have the commitment not to change the contents (including the length), especially if it is important that you know the data is not changing. which can be useful sometimes, but in the case of a struct, it makes it so that the whole struct can't be reassigned, so it's pretty much never a good idea IMHO to have a struct with const or immutable members - Why that conclusion? That is, why should reassignment of S take priority over stable data used by S? For example, take something like a BalanceSheetForecaster which takes a BalanceSheet as input in its ctor. Isn't it important that the numerous queries on and forecasts by the BalanceSheetForecaster be on *exactly* the same data? but having them be tail-const or tail-immutable still makes it so that what they refer to gets all of the benefits of const or immutable without restricting the struct. I appreciate the explanation and think I understand the benefit of tail-const better. You would not easily be able to store modifiable collections of BalanceSheetForecasters, unless you did it with pointers. But the focus of the discussion seems to be on immutable(T)[] which is my fault for choosing the first and easiest type of aliasing I could in my example. I think the slice is really a special case when it comes to aliasing. With immutable(T)[] you have the benefit of not having to worry about aliasing because of the way it is implemented - the contiguous nature and copy on write semantics. But this is not the general case is it? For example, do the same arguments hold for associative arrays? struct S { immutable string[string] aarr; } Doesn't using immutable there present the same problem as with the slice? S is no longer assignable. But who would recommend not using immutable in this case if you want aarr to be stable. If you do not use immutable then who knows when your array will grow without your expecting it? At least with the slice your memory safety is in the control of your module if you make it private. But with associative array it would depend entirely on client code providing the data still having a handle on it.
Re: const and immutable members
On Monday, September 23, 2013 05:18:31 Daniel Davidson wrote: On Sunday, 22 September 2013 at 20:17:03 UTC, Jonathan M Davis which can be useful sometimes, but in the case of a struct, it makes it so that the whole struct can't be reassigned, so it's pretty much never a good idea IMHO to have a struct with const or immutable members - Why that conclusion? That is, why should reassignment of S take priority over stable data used by S? For example, take something like a BalanceSheetForecaster which takes a BalanceSheet as input in its ctor. Isn't it important that the numerous queries on and forecasts by the BalanceSheetForecaster be on *exactly* the same data? If any of a struct's members are const, you reassign them in a postblit constructor, meaning that if they're reference types, you can't copy them. Dynamic arrays of S become almost useless (and static arrays _definitely become useless), because once any value of type S is initialized it can't be assigned. So, if you have S[12] foo; or auto bar = new S[](17); you can't reassign any of the elements in those arrays. Best case, you can mutate their members that aren't const or immutable, but all of their const and immutable members are stuck referring to the value in S.init. Anywhere that involves S.init stops working properly, because you can't change any S's that were default-initialized with S.init to something else. So, outside of the most basic cases where you just put an S on the stack by itself and don't pass it to anything or put it in an array or anything like that, you start running into trouble, because you can't change the value of S. Constrast that with where none of the member variables are const or immutable (or at most are tail-const or tail-immutable), and you can only not assign S when it's a const S or immutable S. In that sort of situation, you can often create an S as mutable and then cast it to const or immutable and get around the problems with S.init. e.g. auto temp = new S[](3); temp[0] = baz(); temp[1] = S(12); temp[2] = blah(); auto bar = assumeUnique(temp); bar and all of its elmeents are now immutable, but you could actually tweak them initially, whereas if any of the member variables were actually fully const or immutable, you couldn't change any of them from their init value. but having them be tail-const or tail-immutable still makes it so that what they refer to gets all of the benefits of const or immutable without restricting the struct. I appreciate the explanation and think I understand the benefit of tail-const better. You would not easily be able to store modifiable collections of BalanceSheetForecasters, unless you did it with pointers. But the focus of the discussion seems to be on immutable(T)[] which is my fault for choosing the first and easiest type of aliasing I could in my example. I think the slice is really a special case when it comes to aliasing. With immutable(T)[] you have the benefit of not having to worry about aliasing because of the way it is implemented - the contiguous nature and copy on write semantics. But this is not the general case is it? For example, do the same arguments hold for associative arrays? struct S { immutable string[string] aarr; } Doesn't using immutable there present the same problem as with the slice? S is no longer assignable. But who would recommend not using immutable in this case if you want aarr to be stable. If you do not use immutable then who knows when your array will grow without your expecting it? At least with the slice your memory safety is in the control of your module if you make it private. But with associative array it would depend entirely on client code providing the data still having a handle on it. Of course, it's the same for AAs. Or classes. Or pointers. Or int. Or float. It's the same for _any_ type. If you make any of them fully immutable, then you can't reassign the struct, which makes the struct unusable in a number of situations. But if your concern is client code messing with your member variable, then don't give them access to it in the first place. Encapsulate it properly, and use property functions or getters and setters to access it. If all you provide is a getter property or getter function and no setters, then they can't assign to it. And if it's a reference type, all you have to do is return a const reference to it rather than a mutable one, and client code won't be able to alter it. And in most cases, using tail-const also solves the problem, because then the reference can be altered but not the data. AAs are one of the few cases where that's not true, because there really isn't a way to have a tail- const AA (not without an AA equivalent to std.typecons.Rebindable anyway). But it works with pointers and arrays just fine, and it works with classes if you use std.typecons.Rebindable. Just return a mutable reference to const or immutable
Multiline String Literals without linefeeds?
In C/C++ in the presence of the preprocessor a string char foo[] = \ long\ string\ without\ linefeeds\ ; Is translated by the preprocessor to char foo[] = longstringwithoutlinefeeds; is there a similar mechanism in D? Or should I do... string foo = long string without linefeeds ;
backtrace_symbols should be called only when exception thrown
in src/druntime/src/core/runtime.d, backtrace_symbols is called in DefaultTraceInfo constructor. Shouldn't it be called only when exception is thrown, to speed up the case when the exception is not thrown?