digitalmars.D.learn - Immutability and other attributes, please review
- Roman D. Boiko (13/13) Jun 14 2012 I have not much experience in D programming yet, and one of
- Jacob Carlborg (11/24) Jun 14 2012 Just a note on the style. The convention is to but all attributes on
- Roman D. Boiko (8/17) Jun 14 2012 This is the naming convention I introduced for classes and
- Roman D. Boiko (15/17) Jun 14 2012 The other thing I don't like is having to cast everywhere:
- Jonathan M Davis (32/52) Jun 14 2012 I haven't had the chance to look over your code yet, but this looks
- Roman D. Boiko (21/69) Jun 14 2012 OK, clear. Thanks!
- Jacob Carlborg (9/28) Jun 14 2012 If you want that and have it immutable you need to make a deep copy of
- Roman D. Boiko (2/7) Jun 14 2012 Thanks, I'll try that.
- Roman D. Boiko (3/10) Jun 14 2012 But then I will have problems sharing such data structures with
- Roman D. Boiko (4/15) Jun 14 2012 Convenience of usage would be less important than compiler
- Jonathan M Davis (6/25) Jun 14 2012 Well, if you break the compiler guarantees, then your program will not w...
- Jacob Carlborg (4/6) Jun 14 2012 Yes. At least the compiler can't guarantee anything.
- Roman D. Boiko (16/20) Jun 14 2012 [...]
- dennis luehring (6/12) Jun 14 2012 thats sounds very evil - with or without immutable
- Roman D. Boiko (8/24) Jun 14 2012 I agree, just looking how to accomplish my goals. I decided to
- Jonathan M Davis (4/5) Jun 14 2012 auto f = new float;
- Roman D. Boiko (6/11) Jun 14 2012 Except for immutable I would need to cast when passing into a
- Jonathan M Davis (18/33) Jun 14 2012 Yeah. That'll probably work. I wish that you could do
- Timon Gehr (4/9) Jun 14 2012 This seems to be an arbitrary limitation.
- Jonathan M Davis (6/20) Jun 14 2012 I suggested it quite some time ago, and as I recall it was met with a fa...
- Dmitry Olshansky (11/23) Jun 14 2012 That or pack the logic into a pure function, e.g. this should work:
- Jonathan M Davis (11/37) Jun 14 2012 Yeah, I was just thinking that maybe we should make a generic function f...
- Dmitry Olshansky (7/44) Jun 14 2012 I think make new would be more self-explanatory. Ptr doesn't imply heap.
- Jonathan M Davis (4/43) Jun 14 2012 Well, we use make with std.container already for essentially the same th...
- Roman D. Boiko (2/12) Jun 14 2012 Dmitry probably suggested makeNew(...)
- Dmitry Olshansky (4/16) Jun 14 2012 Yup, what he said ^ :)
- Roman D. Boiko (3/16) Jun 14 2012 Am I right that [2.0].ptr (instead of 2.0 could be a struct
- Dmitry Olshansky (4/23) Jun 14 2012 Copying what? One word is surely cheap ;)
- Roman D. Boiko (3/8) Jun 14 2012 That was just curiosity, not objection. Also, struct literal
- Jacob Carlborg (5/10) Jun 14 2012 Do you really need to put a float on the heap? Just pass it around as a
- Roman D. Boiko (5/17) Jun 15 2012 That could be anything. In most cases I'm oversimplifying the
- dennis luehring (20/28) Jun 15 2012 i think he needs to - else he encapsulate the float into an struct which...
- Jacob Carlborg (4/23) Jun 15 2012 Ah, I see.
- Roman D. Boiko (20/60) Jun 15 2012 Well, my case is actually more complicated:
- Dmitry Olshansky (14/65) Jun 15 2012 Suggest you revisit toNode function as it does return something strange...
- Roman D. Boiko (2/15) Jun 15 2012 Thanks, fixed. This is the result of not writing tests first :)
- Jacob Carlborg (5/10) Jun 14 2012 Probably.
- Jonathan M Davis (9/30) Jun 14 2012 That varies considerably from person to person. I don't think that there...
I have not much experience in D programming yet, and one of things which I frequently mess up is usage of various attributes, especially immutable and related. Could anybody make a review my code at https://github.com/roman-d-boiko/functional-data-structures/blob/mast r/fds/persistent.d, https://github.com/roman-d-boiko/dct/blob/master/fe/syntax.d, and https://github.com/roman-d-boiko/dct/blob/master/fe/_/syntax.d with respect to usage of attributes (immutable, const, pure, etc.), contracts, and any other issues. I'm redesigning my previous coding attempts to build D compiler front end, and would like to pay attention to these aspects. Please note that adding DDoc comments has been deferred because I need to learn how to use them.
Jun 14 2012
On 2012-06-14 11:19, Roman D. Boiko wrote:I have not much experience in D programming yet, and one of things which I frequently mess up is usage of various attributes, especially immutable and related. Could anybody make a review my code at https://github.com/roman-d-boiko/functional-data-structures/blob/master/fds/persistent.d, https://github.com/roman-d-boiko/dct/blob/master/fe/syntax.d, and https://github.com/roman-d-boiko/dct/blob/master/fe/_/syntax.d with respect to usage of attributes (immutable, const, pure, etc.), contracts, and any other issues. I'm redesigning my previous coding attempts to build D compiler front end, and would like to pay attention to these aspects. Please note that adding DDoc comments has been deferred because I need to learn how to use them.Just a note on the style. The convention is to but all attributes on front of the return type, except for "const", when "const" is referring to that the method is const and not the return type. Another note. class _Module : Module {...} The underscore is unnecessary if you use fully quailed names: class Module : fe.syntax.Module {...} You can also use renamed imports or aliases. -- /Jacob Carlborg
Jun 14 2012
On Thursday, 14 June 2012 at 09:51:45 UTC, Jacob Carlborg wrote:Just a note on the style. The convention is to but all attributes on front of the return type, except for "const", when "const" is referring to that the method is const and not the return type.OKAnother note. class _Module : Module {...} The underscore is unnecessary if you use fully quailed names: class Module : fe.syntax.Module {...} You can also use renamed imports or aliases.This is the naming convention I introduced for classes and functions which should not be referred from client code (factory methods will be used for creation). I have also put them into a separate folder, named _. By the way, the whole data model is designed to be immutable. Should I replace const with immutable then?
Jun 14 2012
On Thursday, 14 June 2012 at 09:56:08 UTC, Roman D. Boiko wrote:By the way, the whole data model is designed to be immutable. Should I replace const with immutable then?The other thing I don't like is having to cast everywhere: struct Maybe(T) { immutable T* payload; // pointer to data pure nothrow this(T* payload) { this.payload = cast(immutable) payload; } pure nothrow property T front() const in{ assert(!empty); } body{ return cast(T) *payload; } //... } OTOH, I'm not sure making input parameter immutable would be better for the user, same for function return type.
Jun 14 2012
On Thursday, June 14, 2012 12:31:16 Roman D. Boiko wrote:On Thursday, 14 June 2012 at 09:56:08 UTC, Roman D. Boiko wrote:I haven't had the chance to look over your code yet, but this looks _seriously_ suspect. Casting to and from immutable or cast away const are things that should be done _very_ rarely. One of the few times that casting to immutable makes any sense is when you need an object to be mutable while you put it together and then immutable afterwards. But when you do that, that reference or pointer is the _only_ reference to that data. e.g. auto func(size_t numElems) { auto arr = new int[](numElems); foreach(ref e; arr) //do something to initialize e return cast(immutable int[])arr; } Taking a function's parameter (which came from who-knows-where) and casting it to immutable is almost certainly a terrible thing to do. If there are _any_ other references to that data, you will have bugs. immutable is supposed to guarantee that the data is _never_ altered. So, when you cast something to immutable, you're telling the compiler that it's okay to treat that data as immutable and that you will _not_ have any mutable references to that data or alter it in any way. If you do, you'll be breaking the compiler's guarantees. Ideally, you would always construct immutable objects as immutable rather than creating them as mutable and then casting them to immutable, but that's not always possible. And taking your payload, which is immutable, and casting away immutable when you return it from front is truly bad. Casting away const or immutable and then mutating that object is _undefined_ behavior. Do _not_ do it unless you have to and know what you're doing. These stackoverflow questions may help you understand better: http://stackoverflow.com/questions/4219600/logical-const-in-d http://stackoverflow.com/questions/10364837/why-do-i-have-to-cast-this - Jonathan M DavisBy the way, the whole data model is designed to be immutable. Should I replace const with immutable then?The other thing I don't like is having to cast everywhere: struct Maybe(T) { immutable T* payload; // pointer to data pure nothrow this(T* payload) { this.payload = cast(immutable) payload; } pure nothrow property T front() const in{ assert(!empty); } body{ return cast(T) *payload; } //... } OTOH, I'm not sure making input parameter immutable would be better for the user, same for function return type.
Jun 14 2012
On Thursday, 14 June 2012 at 11:11:57 UTC, Jonathan M Davis wrote:I haven't had the chance to look over your code yet, but this looks _seriously_ suspect. Casting to and from immutable or cast away const are things that should be done _very_ rarely. One of the few times that casting to immutable makes any sense is when you need an object to be mutable while you put it together and then immutable afterwards. But when you do that, that reference or pointer is the _only_ reference to that data. e.g. auto func(size_t numElems) { auto arr = new int[](numElems); foreach(ref e; arr) //do something to initialize e return cast(immutable int[])arr; } Taking a function's parameter (which came from who-knows-where) and casting it to immutable is almost certainly a terrible thing to do. If there are _any_ other references to that data, you will have bugs. immutable is supposed to guarantee that the data is _never_ altered. So, when you cast something to immutable, you're telling the compiler that it's okay to treat that data as immutable and that you will _not_ have any mutable references to that data or alter it in any way. If you do, you'll be breaking the compiler's guarantees. Ideally, you would always construct immutable objects as immutable rather than creating them as mutable and then casting them to immutable, but that's not always possible. And taking your payload, which is immutable, and casting away immutable when you return it from front is truly bad. Casting away const or immutable and then mutating that object is _undefined_ behavior. Do _not_ do it unless you have to and know what you're doing. These stackoverflow questions may help you understand better: http://stackoverflow.com/questions/4219600/logical-const-in-d http://stackoverflow.com/questions/10364837/why-do-i-have-to-cast-this - Jonathan M DavisOK, clear. Thanks! I was thinking that casting is bad here, but wanted to give the user ability to pass any object inside constructor. Now I see that this is a bad idea given transitivity of immutable. In .NET readonly applies only to fields inside objects preventing assignments to them from other places than constructors. But I can assign another instance of an object with readonly fields to the same variable. Then I can pass that instance to some constructor and assign it to a readonly field. How to achieve the same in D? As far as I understand, it is not possible for structs with immutable fields, and it is not clear for me about classes. In other words: Does a variable always point to the same place in memory and assigning to it simply copies data to that place? I don't understand whether it is possible to make it point to another place. That would be a mutable variable pointing to a type with immutable fields. After that I want to assign an instance of that type to an immutable field in constructor. Can I do so, or that would be bad?
Jun 14 2012
On 2012-06-14 14:47, Roman D. Boiko wrote:I was thinking that casting is bad here, but wanted to give the user ability to pass any object inside constructor. Now I see that this is a bad idea given transitivity of immutable.If you want that and have it immutable you need to make a deep copy of the passed in object to be safe. You could use const instead and also making the argument const. If an argument is const you can pass both mutable and immutable values, and const of course.In .NET readonly applies only to fields inside objects preventing assignments to them from other places than constructors. But I can assign another instance of an object with readonly fields to the same variable. Then I can pass that instance to some constructor and assign it to a readonly field.You should be able to use const.How to achieve the same in D? As far as I understand, it is not possible for structs with immutable fields, and it is not clear for me about classes. In other words: Does a variable always point to the same place in memory and assigning to it simply copies data to that place? I don't understand whether it is possible to make it point to another place. That would be a mutable variable pointing to a type with immutable fields.That's only possible with pointers in D.After that I want to assign an instance of that type to an immutable field in constructor. Can I do so, or that would be bad?-- /Jacob Carlborg
Jun 14 2012
On Thursday, 14 June 2012 at 13:21:34 UTC, Jacob Carlborg wrote:If you want that and have it immutable you need to make a deep copy of the passed in object to be safe. You could use const instead and also making the argument const. If an argument is const you can pass both mutable and immutable values, and const of course.Thanks, I'll try that.
Jun 14 2012
On Thursday, 14 June 2012 at 13:31:01 UTC, Roman D. Boiko wrote:On Thursday, 14 June 2012 at 13:21:34 UTC, Jacob Carlborg wrote:But then I will have problems sharing such data structures with different threads, correct?If you want that and have it immutable you need to make a deep copy of the passed in object to be safe. You could use const instead and also making the argument const. If an argument is const you can pass both mutable and immutable values, and const of course.Thanks, I'll try that.
Jun 14 2012
On Thursday, 14 June 2012 at 13:33:43 UTC, Roman D. Boiko wrote:On Thursday, 14 June 2012 at 13:31:01 UTC, Roman D. Boiko wrote:Convenience of usage would be less important than compiler guarantees, so it looks like I have to stick to immutable, not const.On Thursday, 14 June 2012 at 13:21:34 UTC, Jacob Carlborg wrote:But then I will have problems sharing such data structures with different threads, correct?If you want that and have it immutable you need to make a deep copy of the passed in object to be safe. You could use const instead and also making the argument const. If an argument is const you can pass both mutable and immutable values, and const of course.Thanks, I'll try that.
Jun 14 2012
On Thursday, June 14, 2012 15:53:45 Roman D. Boiko wrote:On Thursday, 14 June 2012 at 13:33:43 UTC, Roman D. Boiko wrote:Well, if you break the compiler guarantees, then your program will not work properly. const and immutable need to be used in such a way that you do not break the compiler's guarantees. If you're having to cast with const or immutable, then you're probably doing something wrong. - Jonathan M DavisOn Thursday, 14 June 2012 at 13:31:01 UTC, Roman D. Boiko wrote:Convenience of usage would be less important than compiler guarantees, so it looks like I have to stick to immutable, not const.On Thursday, 14 June 2012 at 13:21:34 UTC, Jacob Carlborg wrote:But then I will have problems sharing such data structures with different threads, correct?If you want that and have it immutable you need to make a deep copy of the passed in object to be safe. You could use const instead and also making the argument const. If an argument is const you can pass both mutable and immutable values, and const of course.Thanks, I'll try that.
Jun 14 2012
On 2012-06-14 15:33, Roman D. Boiko wrote:But then I will have problems sharing such data structures with different threads, correct?Yes. At least the compiler can't guarantee anything. -- /Jacob Carlborg
Jun 14 2012
On Thursday, 14 June 2012 at 12:47:34 UTC, Roman D. Boiko wrote:On Thursday, 14 June 2012 at 11:11:57 UTC, Jonathan M Davis wrote:[...][...] I've tried to convert return types of all functions to immutable to prevent the need for casting: https://github.com/roman-d-boiko/functional-data-structures/commit/98c317b59b329fe06ffae4fc4c4ab338541e3321 I would be more happy to have them mutable with immutable fields. But since I return data stored in the immutable field, I had to cast away immutable before returning, and cast to immutable in constructor, so I gave up. But now, with everything immutable, I had to comment out several test cases. I cannot pass an immutable struct allocated on stack, into a method by reference, and then store a pointer to it, because compiler says it is not an l-value. Should I allocate it on heap? Or get rid of functions taking parameter by ref, and use only those which take a pointer?- Jonathan M DavisOK, clear. Thanks!
Jun 14 2012
Am 14.06.2012 15:26, schrieb Roman D. Boiko:But now, with everything immutable, I had to comment out several test cases. I cannot pass an immutable struct allocated on stack, into a method by reference, and then store a pointer to it,thats sounds very evil - with or without immutable how should that work anyway?because compiler says it is not an l-value. Should I allocate it on heap? Or get rid of functions taking parameter by ref, and use only those which take a pointer?i would use the heap and ref - else you need to copy, the pointer would also not work if your struct is still in the stack - or does the stack live long enough?
Jun 14 2012
On Thursday, 14 June 2012 at 15:21:53 UTC, dennis luehring wrote:Am 14.06.2012 15:26, schrieb Roman D. Boiko:I agree, just looking how to accomplish my goals. I decided to get rid of casting, and will store everything on heap. I don't know how to put a variable of type float to the heap, and thought that it would be nice to allow the user to pass anything inside, but copy when that is not an l-value. I posted another question: http://forum.dlang.org/thread/nsishethfwgxygsmzjwi forum.dlang.orgBut now, with everything immutable, I had to comment out several test cases. I cannot pass an immutable struct allocated on stack, into a method by reference, and then store a pointer to it,thats sounds very evil - with or without immutable how should that work anyway?because compiler says it is not an l-value. Should I allocate it on heap? Or get rid of functions taking parameter by ref, and use only those which take a pointer?i would use the heap and ref - else you need to copy, the pointer would also not work if your struct is still in the stack - or does the stack live long enough?
Jun 14 2012
On Thursday, June 14, 2012 17:32:03 Roman D. Boiko wrote:I don't know how to put a variable of type float to the heapauto f = new float; *f = 2.1; - Jonathan M Davis
Jun 14 2012
On Thursday, 14 June 2012 at 16:24:43 UTC, Jonathan M Davis wrote:On Thursday, June 14, 2012 17:32:03 Roman D. Boiko wrote:Except for immutable I would need to cast when passing into a function. That's dangerous, given that *f might be changed later. But looks like Timon's suggestion from my other question should work. immutable a = [2.1].ptr;I don't know how to put a variable of type float to the heapauto f = new float; *f = 2.1; - Jonathan M Davis
Jun 14 2012
On Thursday, June 14, 2012 18:32:18 Roman D. Boiko wrote:On Thursday, 14 June 2012 at 16:24:43 UTC, Jonathan M Davis wrote:Yeah. That'll probably work. I wish that you could do auto f = new float(2.1); and therefore auto f = new immutable(float)(2.1); but you can't. You _can_ do auto f = new float; *f = 2.1; immutable g = cast(immutable float*)f; and that's safe, because there are no other references to the data, but it's certainly not all that desirable. The slightly more idomatic way to do it is auto f = new float; *f = 2.1; immutable g = std.exception.assumeUnique(f); But it's doing the same thing and you have to worry about the same safety issues. However, if Timon's suggestion works, that's great. - Jonathan M DavisOn Thursday, June 14, 2012 17:32:03 Roman D. Boiko wrote:Except for immutable I would need to cast when passing into a function. That's dangerous, given that *f might be changed later. But looks like Timon's suggestion from my other question should work. immutable a = [2.1].ptr;I don't know how to put a variable of type float to the heapauto f = new float; *f = 2.1; - Jonathan M Davis
Jun 14 2012
On 06/14/2012 06:42 PM, Jonathan M Davis wrote:I wish that you could do auto f = new float(2.1); and therefore auto f = new immutable(float)(2.1); but you can't.This seems to be an arbitrary limitation. Imho it should be fixed. Probably it was missed because allocating a primitive type on the heap is not a very common operation.
Jun 14 2012
On Friday, June 15, 2012 00:24:15 Timon Gehr wrote:On 06/14/2012 06:42 PM, Jonathan M Davis wrote:I suggested it quite some time ago, and as I recall it was met with a fair bit of negativity. I don't remember why or who said what. Maybe Walter could be talked into it. I don't know. Personally, I think that it would be the perfectly natural way to do it and find it very bizarre that you can't. - Jonathan M DavisI wish that you could do auto f = new float(2.1); and therefore auto f = new immutable(float)(2.1); but you can't.This seems to be an arbitrary limitation. Imho it should be fixed. Probably it was missed because allocating a primitive type on the heap is not a very common operation.
Jun 14 2012
On 14.06.2012 20:32, Roman D. Boiko wrote:On Thursday, 14 June 2012 at 16:24:43 UTC, Jonathan M Davis wrote:That or pack the logic into a pure function, e.g. this should work: immutable ap = newPureFloat(3.1415); float* newPureFloat(float val)pure { float* p = new float; *p = val; return p; } -- Dmitry OlshanskyOn Thursday, June 14, 2012 17:32:03 Roman D. Boiko wrote:Except for immutable I would need to cast when passing into a function. That's dangerous, given that *f might be changed later. But looks like Timon's suggestion from my other question should work. immutable a = [2.1].ptr;I don't know how to put a variable of type float to the heapauto f = new float; *f = 2.1; - Jonathan M Davis
Jun 14 2012
On Thursday, June 14, 2012 21:27:58 Dmitry Olshansky wrote:On 14.06.2012 20:32, Roman D. Boiko wrote:Yeah, I was just thinking that maybe we should make a generic function for this and add it to Phobos. Something like auto makePtr(T, U)(U value) if(is(U : T)) {} auto makePtr(T, Args...)(Args args) {} where the first one works with primitive types and the second one works with structs. Then you could do auto f = makePtr!(immutable float)(2.1); I think that I'll have to see about throwing together something like that tonight and create a pull request. - Jonathan M DavisOn Thursday, 14 June 2012 at 16:24:43 UTC, Jonathan M Davis wrote:That or pack the logic into a pure function, e.g. this should work: immutable ap = newPureFloat(3.1415); float* newPureFloat(float val)pure { float* p = new float; *p = val; return p; }On Thursday, June 14, 2012 17:32:03 Roman D. Boiko wrote:Except for immutable I would need to cast when passing into a function. That's dangerous, given that *f might be changed later. But looks like Timon's suggestion from my other question should work. immutable a = [2.1].ptr;I don't know how to put a variable of type float to the heapauto f = new float; *f = 2.1; - Jonathan M Davis
Jun 14 2012
On 14.06.2012 21:43, Jonathan M Davis wrote:On Thursday, June 14, 2012 21:27:58 Dmitry Olshansky wrote:I think make new would be more self-explanatory. Ptr doesn't imply heap. Other then this, it looks useful. (I'd love to see an optional allocator parameter... but have to wait I guess)On 14.06.2012 20:32, Roman D. Boiko wrote:Yeah, I was just thinking that maybe we should make a generic function for this and add it to Phobos. Something like auto makePtr(T, U)(U value) if(is(U : T)) {} auto makePtr(T, Args...)(Args args) {}On Thursday, 14 June 2012 at 16:24:43 UTC, Jonathan M Davis wrote:That or pack the logic into a pure function, e.g. this should work: immutable ap = newPureFloat(3.1415); float* newPureFloat(float val)pure { float* p = new float; *p = val; return p; }On Thursday, June 14, 2012 17:32:03 Roman D. Boiko wrote:Except for immutable I would need to cast when passing into a function. That's dangerous, given that *f might be changed later. But looks like Timon's suggestion from my other question should work. immutable a = [2.1].ptr;I don't know how to put a variable of type float to the heapauto f = new float; *f = 2.1; - Jonathan M Daviswhere the first one works with primitive types and the second one works with structs. Then you could do auto f = makePtr!(immutable float)(2.1); I think that I'll have to see about throwing together something like that tonight and create a pull request. - Jonathan M Davis-- Dmitry Olshansky
Jun 14 2012
On Thursday, June 14, 2012 21:50:31 Dmitry Olshansky wrote:On 14.06.2012 21:43, Jonathan M Davis wrote:Well, we use make with std.container already for essentially the same thing, only it's specifically for containers. - Jonathan M DavisOn Thursday, June 14, 2012 21:27:58 Dmitry Olshansky wrote:I think make new would be more self-explanatory. Ptr doesn't imply heap. Other then this, it looks useful. (I'd love to see an optional allocator parameter... but have to wait I guess)On 14.06.2012 20:32, Roman D. Boiko wrote:Yeah, I was just thinking that maybe we should make a generic function for this and add it to Phobos. Something like auto makePtr(T, U)(U value) if(is(U : T)) {} auto makePtr(T, Args...)(Args args) {}On Thursday, 14 June 2012 at 16:24:43 UTC, Jonathan M Davis wrote:That or pack the logic into a pure function, e.g. this should work: immutable ap = newPureFloat(3.1415); float* newPureFloat(float val)pure { float* p = new float; *p = val; return p; }On Thursday, June 14, 2012 17:32:03 Roman D. Boiko wrote:Except for immutable I would need to cast when passing into a function. That's dangerous, given that *f might be changed later. But looks like Timon's suggestion from my other question should work. immutable a = [2.1].ptr;I don't know how to put a variable of type float to the heapauto f = new float; *f = 2.1; - Jonathan M Davis
Jun 14 2012
On Thursday, 14 June 2012 at 18:01:06 UTC, Jonathan M Davis wrote:Dmitry probably suggested makeNew(...)I think make new would be more self-explanatory. Ptr doesn't imply heap. Other then this, it looks useful. (I'd love to see an optional allocator parameter... but have to wait I guess)Well, we use make with std.container already for essentially the same thing, only it's specifically for containers. - Jonathan M Davis
Jun 14 2012
On 14.06.2012 22:03, Roman D. Boiko wrote:On Thursday, 14 June 2012 at 18:01:06 UTC, Jonathan M Davis wrote:Yup, what he said ^ :) -- Dmitry OlshanskyDmitry probably suggested makeNew(...)I think make new would be more self-explanatory. Ptr doesn't imply heap. Other then this, it looks useful. (I'd love to see an optional allocator parameter... but have to wait I guess)Well, we use make with std.container already for essentially the same thing, only it's specifically for containers. - Jonathan M Davis
Jun 14 2012
On Thursday, 14 June 2012 at 17:44:11 UTC, Jonathan M Davis wrote:I was just thinking that maybe we should make a generic function for this and add it to Phobos. Something like auto makePtr(T, U)(U value) if(is(U : T)) {} auto makePtr(T, Args...)(Args args) {} where the first one works with primitive types and the second one works with structs. Then you could do auto f = makePtr!(immutable float)(2.1); I think that I'll have to see about throwing together something like that tonight and create a pull request. - Jonathan M DavisAm I right that [2.0].ptr (instead of 2.0 could be a struct literal) doesn't involve copying, while such function would?
Jun 14 2012
On 14.06.2012 21:57, Roman D. Boiko wrote:On Thursday, 14 June 2012 at 17:44:11 UTC, Jonathan M Davis wrote:Copying what? One word is surely cheap ;) -- Dmitry OlshanskyI was just thinking that maybe we should make a generic function for this and add it to Phobos. Something like auto makePtr(T, U)(U value) if(is(U : T)) {} auto makePtr(T, Args...)(Args args) {} where the first one works with primitive types and the second one works with structs. Then you could do auto f = makePtr!(immutable float)(2.1); I think that I'll have to see about throwing together something like that tonight and create a pull request. - Jonathan M DavisAm I right that [2.0].ptr (instead of 2.0 could be a struct literal) doesn't involve copying, while such function would?
Jun 14 2012
On Thursday, 14 June 2012 at 17:58:25 UTC, Dmitry Olshansky wrote:On 14.06.2012 21:57, Roman D. Boiko wrote:That was just curiosity, not objection. Also, struct literal could correspond to a larger instance.Am I right that [2.0].ptr (instead of 2.0 could be a struct literal) doesn't involve copying, while such function would?Copying what? One word is surely cheap ;)
Jun 14 2012
On 2012-06-14 17:32, Roman D. Boiko wrote:I agree, just looking how to accomplish my goals. I decided to get rid of casting, and will store everything on heap. I don't know how to put a variable of type float to the heap, and thought that it would be nice to allow the user to pass anything inside, but copy when that is not an l-value.Do you really need to put a float on the heap? Just pass it around as a value type, it's not like it's a big struct. -- /Jacob Carlborg
Jun 14 2012
On Friday, 15 June 2012 at 06:25:59 UTC, Jacob Carlborg wrote:On 2012-06-14 17:32, Roman D. Boiko wrote:That could be anything. In most cases I'm oversimplifying the task. In this particular case I was interested in building collections which can store objects or structs using pointers to them.I agree, just looking how to accomplish my goals. I decided to get rid of casting, and will store everything on heap. I don't know how to put a variable of type float to the heap, and thought that it would be nice to allow the user to pass anything inside, but copy when that is not an l-value.Do you really need to put a float on the heap? Just pass it around as a value type, it's not like it's a big struct.
Jun 15 2012
Am 15.06.2012 08:25, schrieb Jacob Carlborg:On 2012-06-14 17:32, Roman D. Boiko wrote:i think he needs to - else he encapsulate the float into an struct which is then also on the heap (ast/whatever) nodex -> float nodey -> string nodez -> int nodew -> double etc. in this example a node can contain from n types values - how would you solve that? or better what is the smallest(maybe fastest) representation there need to be a queryable tree in the end - so there is a need to hold the values - yes he can copy by value - but into whom? in the end it will be an variant-like type (with members for each type) on heap - whichs is not that good because that will cost much more mem or something like an class FloatValue -> NodeValue -> Value oop-hierachy whichs also will get onto the heap i would try to use something like an base-types pool for all the small float,double,int,string etc values... and pointer to this pool - or just use the heap :)I agree, just looking how to accomplish my goals. I decided to get rid of casting, and will store everything on heap. I don't know how to put a variable of type float to the heap, and thought that it would be nice to allow the user to pass anything inside, but copy when that is not an l-value.Do you really need to put a float on the heap? Just pass it around as a value type, it's not like it's a big struct.
Jun 15 2012
On 2012-06-15 10:30, dennis luehring wrote:i think he needs to - else he encapsulate the float into an struct which is then also on the heap (ast/whatever) nodex -> float nodey -> string nodez -> int nodew -> double etc. in this example a node can contain from n types values - how would you solve that? or better what is the smallest(maybe fastest) representation there need to be a queryable tree in the end - so there is a need to hold the values - yes he can copy by value - but into whom? in the end it will be an variant-like type (with members for each type) on heap - whichs is not that good because that will cost much more mem or something like an class FloatValue -> NodeValue -> Value oop-hierachy whichs also will get onto the heap i would try to use something like an base-types pool for all the small float,double,int,string etc values... and pointer to this pool - or just use the heap :)Ah, I see. -- /Jacob Carlborg
Jun 15 2012
On Friday, 15 June 2012 at 08:31:08 UTC, dennis luehring wrote:Am 15.06.2012 08:25, schrieb Jacob Carlborg:Well, my case is actually more complicated: https://github.com/roman-d-boiko/dct/blob/master/fe/syntax.d Node is a struct that holds: * instances of Syntax **classes** (these are immutable AST nodes without identity; please don't confuse Node which is a struct and node which is a general term for part of a tree) * information about their positions of Syntax nodes in source code, * and links to parent Node instances. This way we have the ability to reuse most of Syntax nodes during incremental source code edits, only regenerating lightweight Node structs that introduce unique identity to those Syntax nodes. As I already mentioned, Syntax nodes are immutable classes. They have to be polymorphic (thus classes), but they are value types without identity. They form immutable trees where each parent knows its children. They don't know their positions in source code, only their widths. Node structs know their parent Node structs and on demand can quickly compute their children as Node[] using information about children from their Syntax field.On 2012-06-14 17:32, Roman D. Boiko wrote:i think he needs to - else he encapsulate the float into an struct which is then also on the heap (ast/whatever) nodex -> float nodey -> string nodez -> int nodew -> double etc. in this example a node can contain from n types values - how would you solve that? or better what is the smallest(maybe fastest) representation there need to be a queryable tree in the end - so there is a need to hold the values - yes he can copy by value - but into whom? in the end it will be an variant-like type (with members for each type) on heap - whichs is not that good because that will cost much more mem or something like an class FloatValue -> NodeValue -> Value oop-hierachy whichs also will get onto the heap i would try to use something like an base-types pool for all the small float,double,int,string etc values... and pointer to this pool - or just use the heap :)I agree, just looking how to accomplish my goals. I decided to get rid of casting, and will store everything on heap. I don't know how to put a variable of type float to the heap, and thought that it would be nice to allow the user to pass anything inside, but copy when that is not an l-value.Do you really need to put a float on the heap? Just pass it around as a value type, it's not like it's a big struct.
Jun 15 2012
On 15.06.2012 12:50, Roman D. Boiko wrote:On Friday, 15 June 2012 at 08:31:08 UTC, dennis luehring wrote:Suggest you revisit toNode function as it does return something strange :) Just looking at first - last lines: pure nothrow auto toNode(R)(R range, immutable(Maybe!Node) parent) if(isInputRange!R && hasLength!R) .... auto result = new Node[](range.length); foreach(e; range) result ~= toNode2(e); return cast(immutable) range; // <<<<---- WAT } And no need to cast to immutable, compiler will infer things automatically since it's pure. (and correctly for both mutable/immutable) -- Dmitry OlshanskyAm 15.06.2012 08:25, schrieb Jacob Carlborg:Well, my case is actually more complicated: https://github.com/roman-d-boiko/dct/blob/master/fe/syntax.d Node is a struct that holds: * instances of Syntax **classes** (these are immutable AST nodes without identity; please don't confuse Node which is a struct and node which is a general term for part of a tree) * information about their positions of Syntax nodes in source code, * and links to parent Node instances.On 2012-06-14 17:32, Roman D. Boiko wrote:i think he needs to - else he encapsulate the float into an struct which is then also on the heap (ast/whatever) nodex -> float nodey -> string nodez -> int nodew -> double etc. in this example a node can contain from n types values - how would you solve that? or better what is the smallest(maybe fastest) representation there need to be a queryable tree in the end - so there is a need to hold the values - yes he can copy by value - but into whom? in the end it will be an variant-like type (with members for each type) on heap - whichs is not that good because that will cost much more mem or something like an class FloatValue -> NodeValue -> Value oop-hierachy whichs also will get onto the heap i would try to use something like an base-types pool for all the small float,double,int,string etc values... and pointer to this pool - or just use the heap :)I agree, just looking how to accomplish my goals. I decided to get rid of casting, and will store everything on heap. I don't know how to put a variable of type float to the heap, and thought that it would be nice to allow the user to pass anything inside, but copy when that is not an l-value.Do you really need to put a float on the heap? Just pass it around as a value type, it's not like it's a big struct.
Jun 15 2012
On Friday, 15 June 2012 at 10:01:42 UTC, Dmitry Olshansky wrote:Suggest you revisit toNode function as it does return something strange :) Just looking at first - last lines: pure nothrow auto toNode(R)(R range, immutable(Maybe!Node) parent) if(isInputRange!R && hasLength!R) .... auto result = new Node[](range.length); foreach(e; range) result ~= toNode2(e); return cast(immutable) range; // <<<<---- WAT } And no need to cast to immutable, compiler will infer things automatically since it's pure. (and correctly for both mutable/immutable)Thanks, fixed. This is the result of not writing tests first :)
Jun 15 2012
On 2012-06-14 11:56, Roman D. Boiko wrote:This is the naming convention I introduced for classes and functions which should not be referred from client code (factory methods will be used for creation). I have also put them into a separate folder, named _.Fair enough.By the way, the whole data model is designed to be immutable. Should I replace const with immutable then?Probably. -- /Jacob Carlborg
Jun 14 2012
On Thursday, June 14, 2012 11:51:44 Jacob Carlborg wrote:On 2012-06-14 11:19, Roman D. Boiko wrote:That varies considerably from person to person. I don't think that there's really any agreed upon order other than the fact that most people agree that const should go on the right when it's modifying the function. Personally, I put almost everything on the right-hand side (the only exceptions being static, property, and the access modifiers). It is true, however, that a number of people put the attributes before the return type. I really wish that they wouldn't though. - Jonathan M DavisI have not much experience in D programming yet, and one of things which I frequently mess up is usage of various attributes, especially immutable and related. Could anybody make a review my code at https://github.com/roman-d-boiko/functional-data-structures/blob/master/fd s/persistent.d, https://github.com/roman-d-boiko/dct/blob/master/fe/syntax.d, and https://github.com/roman-d-boiko/dct/blob/master/fe/_/syntax.d with respect to usage of attributes (immutable, const, pure, etc.), contracts, and any other issues. I'm redesigning my previous coding attempts to build D compiler front end, and would like to pay attention to these aspects. Please note that adding DDoc comments has been deferred because I need to learn how to use them.Just a note on the style. The convention is to but all attributes on front of the return type, except for "const", when "const" is referring to that the method is const and not the return type.
Jun 14 2012