www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Immutability and other attributes, please review

reply "Roman D. Boiko" <rb d-coding.com> writes:
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
parent reply Jacob Carlborg <doob me.com> writes:
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
next sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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.
OK
 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.
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
next sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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:
 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.
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 Davis
Jun 14 2012
parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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 Davis
OK, 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
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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
parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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:
 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.
But then I will have problems sharing such data structures with different threads, correct?
Jun 14 2012
next sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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:
 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.
But then I will have problems sharing such data structures with different threads, correct?
Convenience of usage would be less important than compiler guarantees, so it looks like I have to stick to immutable, not const.
Jun 14 2012
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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:
 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:
 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.
But then I will have problems sharing such data structures with different threads, correct?
Convenience of usage would be less important than compiler guarantees, so it looks like I have to stick to immutable, not const.
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 Davis
Jun 14 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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:
[...]
 - Jonathan M Davis
OK, clear. Thanks!
[...] 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?
Jun 14 2012
parent reply dennis luehring <dl.soluz gmx.net> writes:
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
parent reply "Roman D. Boiko" <rb d-coding.com> writes:
On Thursday, 14 June 2012 at 15:21:53 UTC, dennis luehring wrote:
 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?
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.org
Jun 14 2012
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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 heap
auto f = new float; *f = 2.1; - Jonathan M Davis
Jun 14 2012
parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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:
 I don't know how to put a variable of type float to the heap
auto f = new float; *f = 2.1; - Jonathan M Davis
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;
Jun 14 2012
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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:
 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 heap
auto f = new float; *f = 2.1; - Jonathan M Davis
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;
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 Davis
Jun 14 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, June 15, 2012 00:24:15 Timon Gehr wrote:
 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.
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 Davis
Jun 14 2012
prev sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.06.2012 20:32, Roman D. Boiko wrote:
 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:
 I don't know how to put a variable of type float to the heap
auto f = new float; *f = 2.1; - Jonathan M Davis
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;
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 Olshansky
Jun 14 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, June 14, 2012 21:27:58 Dmitry Olshansky wrote:
 On 14.06.2012 20:32, Roman D. Boiko wrote:
 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:
 I don't know how to put a variable of type float to the heap
auto f = new float; *f = 2.1; - Jonathan M Davis
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;
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; }
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 Davis
Jun 14 2012
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.06.2012 21:43, Jonathan M Davis wrote:
 On Thursday, June 14, 2012 21:27:58 Dmitry Olshansky wrote:
 On 14.06.2012 20:32, Roman D. Boiko wrote:
 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:
 I don't know how to put a variable of type float to the heap
auto f = new float; *f = 2.1; - Jonathan M Davis
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;
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; }
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) {}
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)
 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 Davis
-- Dmitry Olshansky
Jun 14 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, June 14, 2012 21:50:31 Dmitry Olshansky wrote:
 On 14.06.2012 21:43, Jonathan M Davis wrote:
 On Thursday, June 14, 2012 21:27:58 Dmitry Olshansky wrote:
 On 14.06.2012 20:32, Roman D. Boiko wrote:
 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:
 I don't know how to put a variable of type float to the heap
auto f = new float; *f = 2.1; - Jonathan M Davis
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;
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; }
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) {}
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
parent reply "Roman D. Boiko" <rb d-coding.com> writes:
On Thursday, 14 June 2012 at 18:01:06 UTC, Jonathan M Davis 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)
Well, we use make with std.container already for essentially the same thing, only it's specifically for containers. - Jonathan M Davis
Dmitry probably suggested makeNew(...)
Jun 14 2012
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.06.2012 22:03, Roman D. Boiko wrote:
 On Thursday, 14 June 2012 at 18:01:06 UTC, Jonathan M Davis 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)
Well, we use make with std.container already for essentially the same thing, only it's specifically for containers. - Jonathan M Davis
Dmitry probably suggested makeNew(...)
Yup, what he said ^ :) -- Dmitry Olshansky
Jun 14 2012
prev sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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 Davis
Am 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
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.06.2012 21:57, Roman D. Boiko wrote:
 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 Davis
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 ;) -- Dmitry Olshansky
Jun 14 2012
parent "Roman D. Boiko" <rb d-coding.com> writes:
On Thursday, 14 June 2012 at 17:58:25 UTC, Dmitry Olshansky wrote:
 On 14.06.2012 21:57, Roman D. Boiko wrote:
 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 ;)
That was just curiosity, not objection. Also, struct literal could correspond to a larger instance.
Jun 14 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
next sibling parent "Roman D. Boiko" <rb d-coding.com> writes:
On Friday, 15 June 2012 at 06:25:59 UTC, Jacob Carlborg wrote:
 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.
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.
Jun 15 2012
prev sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 15.06.2012 08:25, schrieb Jacob Carlborg:
 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.
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 :)
Jun 15 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
On Friday, 15 June 2012 at 08:31:08 UTC, dennis luehring wrote:
 Am 15.06.2012 08:25, schrieb Jacob Carlborg:
 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.
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 :)
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.
Jun 15 2012
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 15.06.2012 12:50, Roman D. Boiko wrote:
 On Friday, 15 June 2012 at 08:31:08 UTC, dennis luehring wrote:
 Am 15.06.2012 08:25, schrieb Jacob Carlborg:
 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.
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 :)
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.
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 Olshansky
Jun 15 2012
parent "Roman D. Boiko" <rb d-coding.com> writes:
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
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, June 14, 2012 11:51:44 Jacob Carlborg wrote:
 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/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.
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 Davis
Jun 14 2012