Re: Class qualifier vs struct qualifier

2018-06-16 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, June 16, 2018 07:13:28 Timoses via Digitalmars-d-learn wrote:
> On Thursday, 14 June 2018 at 17:07:09 UTC, Jonathan M Davis wrote:
> > Sure, it would save you a little bit of typing when you do
> > something like
> >
> > auto foo = new Foo;
> >
> > if makes it immutable for you, but it's at the cost of code
> > clarity.
>
> Why should it even?
>
> Isn't
>
>  immutable class C
>  {
>  int a;
>  }
>
> the same as
>
>  class C
>  {
>  immutable
>  {
>  int a;
>  }
>  }
>
> ?
>
> Does the following code clarify why an instance if immutable
> struct HAS to be immutable while an instance of class does not
> have to be immutable??
>
> immutable struct S {}
> immutable class C {}
>
> void main()
> {
>  S sa = S();
>  pragma(msg, typeof(sa)); // immutable(S)
>  S sb = S();
>  // sa = sb; // Error: cannot modify immutable expression sa
>
>  C ca = new C();
>  pragma(msg, typeof(ca)); // C
>  C cb = new C();
>  ca = cb; // works
> }
>
> Then the question would rather be why
>
> S s = S();  // immutable(S)
>
> does what it seems to be doing..?

It's perfectly legal to do

struct S
{
int i;
immutable int j;
}

and, declaring a variable of that type

S s;

does not result in the type of s being treated as immutable - just the
members. Similarly,

struct S
{
immutable int i;
}

S s;

does not result in s being immutable(S). It's just when the struct itself is
marked as immutable that every variable of that type is suddenly treated as
immutable as well. And of course, with classes, marking the class as
immutable is identical to marking all of its members as immutable. Why
that's not the case for structs, I have no idea.

Regardless, I think that it's a terrible idea to implicitly make a type
immutable everywhere. If I see

S s;

I expect S to be mutable. Sure, it could have const or immutable members
(much as that's generally a terrible idea for structs, because it makes them
non-assignable and potentially non-copyable), but I would never expect the
type to be immutable(S) when the variable is clearly typed as S - just like
I wouldn't expect new S to result in an immutable(S). I was _very_ surprised
to see that the compile treats

immutable struct S
{
}

differently from

struct S
{
immutable:
}

and I really think that it should be fixed so that it doesn't. The fact that

S s;

could ever result in the variable being anything other than S most
definitely breaks the principle of least surprise, and it doesn't match how
the rest of the language works. It's particularly bizarre when you consider
that it doesn't happen when all of the members are immutable if the struct
wasn't directly marked with immutable.

IMHO, even if a type were unusable as anything other than immutable,
variables of that type should still have to be marked with immutable,
otherwise the variable declaration doesn't match the actual type of the
variable, which seems like a terrible idea.

- Jonathan M Davis



Re: Class qualifier vs struct qualifier

2018-06-16 Thread Timoses via Digitalmars-d-learn

On Thursday, 14 June 2018 at 17:07:09 UTC, Jonathan M Davis wrote:
Sure, it would save you a little bit of typing when you do 
something like


auto foo = new Foo;

if makes it immutable for you, but it's at the cost of code 
clarity.


Why should it even?

Isn't

immutable class C
{
int a;
}

the same as

class C
{
immutable
{
int a;
}
}

?

Does the following code clarify why an instance if immutable 
struct HAS to be immutable while an instance of class does not 
have to be immutable??


immutable struct S {}
immutable class C {}

void main()
{
S sa = S();
pragma(msg, typeof(sa)); // immutable(S)
S sb = S();
// sa = sb; // Error: cannot modify immutable expression sa

C ca = new C();
pragma(msg, typeof(ca)); // C
C cb = new C();
ca = cb; // works
}

Then the question would rather be why

S s = S();  // immutable(S)

does what it seems to be doing..?


Re: Class qualifier vs struct qualifier

2018-06-14 Thread David Bennett via Digitalmars-d-learn

On Wednesday, 13 June 2018 at 07:35:25 UTC, RazvanN wrote:

Hello,

I'm having a hard time understanding whether this inconsistency 
is a bug or intended behavior:


immutable class Foo {}
immutable struct Bar {}

void main()
{
import std.stdio : writeln;
Foo a;
Bar b;

writeln("typeof(a): ", typeof(a).stringof);
writeln("typeof(b): ", typeof(b).stringof);
}

prints:

typeof(Foo): Foo
typeof(Bar): immutable(Bar)


It seems like the class storage class is not taken into account 
which leads to some awkward situations like:


immutable class Foo
{
this() {}
}

void main()
{
Foo a = new Foo(); // error: immutable method `this` is not 
callable using a

   // mutable object
}

To make it work I have to add immutable to both sides of the 
expression : immutable Foo a = new immutable Foo(); this is a 
wonder of redundancy. I already declared the class as immutable 
so it shouldn't be possible to have mutable instances of it 
(and it isn't), however I am forced to write the immutable 
twice even though it is pretty obvious that the class cannot be 
mutated.


Just tested and I only seem to need to add the immutable to the 
left of the expression.


https://run.dlang.io/is/EZ7es0

Also with the struct `Bar* b = new Bar();` works fine so i guess 
the discrepancy is because the class ref is mutatable.


Re: Class qualifier vs struct qualifier

2018-06-14 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, June 14, 2018 08:39:48 RazvanN via Digitalmars-d-learn wrote:
> > Honestly, from what I understand of how this works, what I find
> > weird is the struct case. immutable on classes does _not_ make
> > the class itself immutable. It just makes all of its members
> > immutable - hence the error about trying to allocate new Foo
> > instead of new immutable Foo. So, that is exactly what I would
> > expect. And honestly, being able to write Foo and have it imply
> > immutable Foo would get _really_ confusing when reading and
> > debugging code.
>
> Maybe it has something to do with structs being value types and
> classes
> being reference types. If you declare an immutable struct then
> you cannot
> modify it's value, while if you declare a class, the pointer to
> the class
> is mutable, while the class fields are not. This kind of makes
> sense, however
> the thing is that in both situations you are not able to mutate
> any of the
> class/struct fields no matter how you instantiate it, so it is
> really redundant
> to use `immutable` when creating the instance.

Except that it isn't redundant, because without using immutable, it looks
like you're trying to create a mutable object. Would you honestly ever look
at something like

Foo foo;

and expect the object to be immutable? And sadly, looking at the type
declaration isn't even necessarily enough to know that it was marked with
immutable, because someone could have done something dumb like put

immutable:

higher up in the file. Types normally require that you explicitly mark them
as immutable to make them immutable when using them anywhere - including
declaring variables or allocating objects. I don't see why having made all
of the members of the type immutable should change that. It's just extra
magic that makes it harder to read the code. Sure, it would save you a
little bit of typing when you do something like

auto foo = new Foo;

if makes it immutable for you, but it's at the cost of code clarity.

- Jonathan M Davis



Re: Class qualifier vs struct qualifier

2018-06-14 Thread RazvanN via Digitalmars-d-learn
Honestly, from what I understand of how this works, what I find 
weird is the struct case. immutable on classes does _not_ make 
the class itself immutable. It just makes all of its members 
immutable - hence the error about trying to allocate new Foo 
instead of new immutable Foo. So, that is exactly what I would 
expect. And honestly, being able to write Foo and have it imply 
immutable Foo would get _really_ confusing when reading and 
debugging code.


Maybe it has something to do with structs being value types and 
classes
being reference types. If you declare an immutable struct then 
you cannot
modify it's value, while if you declare a class, the pointer to 
the class
is mutable, while the class fields are not. This kind of makes 
sense, however
the thing is that in both situations you are not able to mutate 
any of the
class/struct fields no matter how you instantiate it, so it is 
really redundant

to use `immutable` when creating the instance.

What's bizarre is that marking the struct with immutable would 
affect anything other than its members.


Bar b;

should not claim that typeof(b) is immutable(Bar). b was not 
marked as
immutable. It was listed as Bar, not immutable Bar. So, b 
shouldn't be

immutable.

- Jonathan M Davis





Re: Class qualifier vs struct qualifier

2018-06-13 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, June 13, 2018 14:33:48 Jonathan M Davis via Digitalmars-d-
learn wrote:
> On Wednesday, June 13, 2018 07:35:25 RazvanN via Digitalmars-d-learn 
wrote:
> > Hello,
> >
> > I'm having a hard time understanding whether this inconsistency
> > is a bug or intended behavior:
> >
> > immutable class Foo {}
> > immutable struct Bar {}
> >
> > void main()
> > {
> >
> >  import std.stdio : writeln;
> >  Foo a;
> >  Bar b;
> >
> >  writeln("typeof(a): ", typeof(a).stringof);
> >  writeln("typeof(b): ", typeof(b).stringof);
> >
> > }
> >
> > prints:
> >
> > typeof(Foo): Foo
> > typeof(Bar): immutable(Bar)
> >
> >
> > It seems like the class storage class is not taken into account
> > which leads to some awkward situations like:
> >
> > immutable class Foo
> > {
> >
> >  this() {}
> >
> > }
> >
> > void main()
> > {
> >
> >  Foo a = new Foo(); // error: immutable method `this` is not
> >
> > callable using a
> >
> > // mutable object
> >
> > }
> >
> > To make it work I have to add immutable to both sides of the
> > expression : immutable Foo a = new immutable Foo(); this is a
> > wonder of redundancy. I already declared the class as immutable
> > so it shouldn't be possible to have mutable instances of it (and
> > it isn't), however I am forced to write the immutable twice even
> > though it is pretty obvious that the class cannot be mutated.
>
> Honestly, from what I understand of how this works, what I find weird is
> the struct case. immutable on classes does _not_ make the class itself
> immutable. It just makes all of its members immutable - hence the error
> about trying to allocate new Foo instead of new immutable Foo. So, that
> is exactly what I would expect. And honestly, being able to write Foo and
> have it imply immutable Foo would get _really_ confusing when reading and
> debugging code.
>
> What's bizarre is that marking the struct with immutable would affect
> anything other than its members.
>
> Bar b;
>
> should not claim that typeof(b) is immutable(Bar). b was not marked as
> immutable. It was listed as Bar, not immutable Bar. So, b shouldn't be
> immutable.

https://issues.dlang.org/show_bug.cgi?id=18977

- Jonathan M Davis



Re: Class qualifier vs struct qualifier

2018-06-13 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, June 13, 2018 07:35:25 RazvanN via Digitalmars-d-learn wrote:
> Hello,
>
> I'm having a hard time understanding whether this inconsistency
> is a bug or intended behavior:
>
> immutable class Foo {}
> immutable struct Bar {}
>
> void main()
> {
>  import std.stdio : writeln;
>  Foo a;
>  Bar b;
>
>  writeln("typeof(a): ", typeof(a).stringof);
>  writeln("typeof(b): ", typeof(b).stringof);
> }
>
> prints:
>
> typeof(Foo): Foo
> typeof(Bar): immutable(Bar)
>
>
> It seems like the class storage class is not taken into account
> which leads to some awkward situations like:
>
> immutable class Foo
> {
>  this() {}
> }
>
> void main()
> {
>  Foo a = new Foo(); // error: immutable method `this` is not
> callable using a
> // mutable object
> }
>
> To make it work I have to add immutable to both sides of the
> expression : immutable Foo a = new immutable Foo(); this is a
> wonder of redundancy. I already declared the class as immutable
> so it shouldn't be possible to have mutable instances of it (and
> it isn't), however I am forced to write the immutable twice even
> though it is pretty obvious that the class cannot be mutated.

Honestly, from what I understand of how this works, what I find weird is the
struct case. immutable on classes does _not_ make the class itself
immutable. It just makes all of its members immutable - hence the error
about trying to allocate new Foo instead of new immutable Foo. So, that is
exactly what I would expect. And honestly, being able to write Foo and have
it imply immutable Foo would get _really_ confusing when reading and
debugging code.

What's bizarre is that marking the struct with immutable would affect
anything other than its members.

Bar b;

should not claim that typeof(b) is immutable(Bar). b was not marked as
immutable. It was listed as Bar, not immutable Bar. So, b shouldn't be
immutable.

- Jonathan M Davis



Re: Class qualifier vs struct qualifier

2018-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/13/18 3:35 AM, RazvanN wrote:

Hello,

I'm having a hard time understanding whether this inconsistency is a bug 
or intended behavior:


immutable class Foo {}
immutable struct Bar {}

void main()
{
     import std.stdio : writeln;
     Foo a;
     Bar b;

     writeln("typeof(a): ", typeof(a).stringof);
     writeln("typeof(b): ", typeof(b).stringof);
}

prints:

typeof(Foo): Foo
typeof(Bar): immutable(Bar)


It seems like the class storage class is not taken into account which 
leads to some awkward situations like:


immutable class Foo
{
     this() {}
}

void main()
{
     Foo a = new Foo(); // error: immutable method `this` is not 
callable using a

    // mutable object
}

To make it work I have to add immutable to both sides of the expression 
: immutable Foo a = new immutable Foo(); this is a wonder of redundancy. 
I already declared the class as immutable so it shouldn't be possible to 
have mutable instances of it (and it isn't), however I am forced to 
write the immutable twice even though it is pretty obvious that the 
class cannot be mutated.


Just on the principle of least surprise, I'd call this a bug. I don't 
know what the intention is, but if the intention is for this behavior, 
we should re-visit.


-Steve