View mode: basic / threaded / horizontal-split · Log in · Help
June 14, 2012
Immutability and other attributes, please review
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.
June 14, 2012
Re: Immutability and other attributes, please review
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
June 14, 2012
Re: Immutability and other attributes, please review
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?
June 14, 2012
Re: Immutability and other attributes, please review
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
June 14, 2012
Re: Immutability and other attributes, please review
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.
June 14, 2012
Re: Immutability and other attributes, please review
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
June 14, 2012
Re: Immutability and other attributes, please review
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?
June 14, 2012
Re: Immutability and other attributes, please review
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
June 14, 2012
Re: Immutability and other attributes, please review
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
June 14, 2012
Re: Immutability and other attributes, please review
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?
« First   ‹ Prev
1 2 3 4
Top | Discussion index | About this forum | D home