www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Difference betwee storage class and type (invariant/const)?

reply Robert Fraser <fraserofthenight gmail.com> writes:
Can someone explain to me what the difference is between a storage class and a
type is, with regards to const and invariant? For example, what do these do
differently?

invariant int foo;
invariant(int) foo;

...? I know this is probably second-nature to people with C++ backgrounds, but
I find the documentation quite confusing, as I've only really worked in Java
before.
Jun 18 2007
next sibling parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Robert Fraser wrote:
 Can someone explain to me what the difference is between a storage class and a
type is, with regards to const and invariant? For example, what do these do
differently?
 
 invariant int foo;
 invariant(int) foo;
 
 ...? I know this is probably second-nature to people with C++ backgrounds, but
I find the documentation quite confusing, as I've only really worked in Java
before.

Between those? Nothing. The difference is here: invariant int* foo; invariant(int)* bar; The former is equivalent to: invariant(int*) foo; That is, when it is used as a storage class, it applies to the whole type. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Jun 18 2007
next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Ah, I see, thanks! So the difference is mainly when it applies to a
naturally-reference type such as an object?

"const(Foo) bar" only the data inside the object is const, while with "const
Foo bar", both the data and the reference are constant?

Kirk McDonald Wrote:

 Robert Fraser wrote:
 Can someone explain to me what the difference is between a storage class and a
type is, with regards to const and invariant? For example, what do these do
differently?
 
 invariant int foo;
 invariant(int) foo;
 
 ...? I know this is probably second-nature to people with C++ backgrounds, but
I find the documentation quite confusing, as I've only really worked in Java
before.

Between those? Nothing. The difference is here: invariant int* foo; invariant(int)* bar; The former is equivalent to: invariant(int*) foo; That is, when it is used as a storage class, it applies to the whole type. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org

Jun 18 2007
prev sibling parent Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 For example, what do these do differently?
 
 invariant int foo;
 invariant(int) foo;

Nothing.

I thought so too, but experimenting with the new compiler gives void main() { invariant int foo; invariant(int) bar; static if(is(typeof(foo) == typeof(bar))) pragma(msg, "Same types"); bar = 1; foo = 1; // line 9 } dmd invartest Same types invartest.d(9): Error: constant foo is not an lvalue So... they are the same type but behave differently? Is that a bug? Christian
Jun 19 2007
prev sibling next sibling parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 invariant int foo;

This is like a compile-time constant invariant int foo = 1; foo = 2; // Fails: foo is not an lvalue auto fooptr = &foo; // Fails: 1 is not an lvalue
 invariant(int) foo;

This is something else and some of its behaviour I don't understand. invariant(int) foo = 1; // typeof(foo) seems to be int? foo = 2; // ok! auto fooptr = &foo; *fooptr = 3; // the docs say this should fail, but it compiles fine Note that invariant(int)* fooptr = &foo; fails with "cannot implicitly convert expression (& foo) of type int* to invariant(int)*", although the documentation says that should work. So making a type invariant seems to have no effect on plain data at the moment. It makes a difference for data containing references though: struct S { int x; int* p; } invariant(S) bar; bar.x = 1; // ok *bar.p = 1; // fails: not mutable auto barptr = &bar; //typeof(barptr) is invariant(S)* barptr.x = 2 // fails: not mutable Note also that static if(is(invariant(S*) == invariant(S)*)) does not pass, but invariant(S*) barptr2 = &bar; static if(is(typeof(barptr2) == invariant(S)*)) passes... is there a logical explanation for that? Cheers, Christian
Jun 19 2007
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Christian Kamm Wrote:

[...]

 struct S { int x; int* p; }
 invariant(S) bar;
 bar.x = 1; // ok
 *bar.p = 1; // fails: not mutable

Wait, so non-reference-types are mutable, but the data pointed to by reference types isn't...? Hwah...? I understand that structs are value types, but does this mean that the values within the struct can be changed while the values the struct points to can't be? And this differs from a class because a class is a reference type by default...? So, wait, struct Foo { int x; } class Bar { int x; } const(Foo) foo; const(Bar) bar = new Bar(); foo.x = 5; // Ok...? bar.x = 5; // Compile-time error...? Weird. I've always just used structs as stack-allocated classes without inheritence, constructors, or the overhead. Now there's another difference to worry about, I guess because they're value types...
 static if(is(invariant(S*) == invariant(S)*))
 does not pass, but
 invariant(S*) barptr2 = &bar;
 static if(is(typeof(barptr2) == invariant(S)*))
 passes... is there a logical explanation for that?

Now I'm even more confused... I'm from a Java background, so I don't really understand constness already, and the implementation here seems to be way weird... Anyways, thanks all... I guess I'll wait until the implementation matches the docs and there's a tutorial or something out there which explains this all without bringing up a lot of gray areas.
Jun 19 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Robert Fraser wrote:
 Christian Kamm Wrote:
 
 [...]
 
 struct S { int x; int* p; }
 invariant(S) bar;
 bar.x = 1; // ok
 *bar.p = 1; // fails: not mutable

Wait, so non-reference-types are mutable, but the data pointed to by reference types isn't...? Hwah...? I understand that structs are value types, but does this mean that the values within the struct can be changed while the values the struct points to can't be? And this differs from a class because a class is a reference type by default...? So, wait, struct Foo { int x; } class Bar { int x; } const(Foo) foo; const(Bar) bar = new Bar(); foo.x = 5; // Ok...? bar.x = 5; // Compile-time error...? Weird. I've always just used structs as stack-allocated classes without inheritence, constructors, or the overhead. Now there's another difference to worry about, I guess because they're value types...
 static if(is(invariant(S*) == invariant(S)*))
 does not pass, but
 invariant(S*) barptr2 = &bar;
 static if(is(typeof(barptr2) == invariant(S)*))
 passes... is there a logical explanation for that?

Now I'm even more confused... I'm from a Java background, so I don't really understand constness already, and the implementation here seems to be way weird... Anyways, thanks all... I guess I'll wait until the implementation matches the docs and there's a tutorial or something out there which explains this all without bringing up a lot of gray areas.

Does this help? It was written before the release of D 2.0, but it does try to explain the difference between the different kinds of const: http://while-nan.blogspot.com/2007/06/you-cant-touch-this.html As for the second thing, I'm not entirely sure either, but given that invariant(char)[] seems to have the behaviour one would expect from invariant(char[]), it could be that there's simply no difference and invariant(char)[] is the canonical form in the compiler. -- Daniel
Jun 19 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
Yup, that sort of makes sense, thanks.

Now I'm just wierded out by the whole thing where struct members can change
value but things pointed to by the struct members can't. But I'll get used to
it eventually. I think for the time being, I'll just put "in" on all my method
signatures, remove it when the compiler complains, and not worry about the rest.

Daniel Keep Wrote:

 
 
 Robert Fraser wrote:
 Christian Kamm Wrote:
 
 [...]
 
 struct S { int x; int* p; }
 invariant(S) bar;
 bar.x = 1; // ok
 *bar.p = 1; // fails: not mutable

Wait, so non-reference-types are mutable, but the data pointed to by reference types isn't...? Hwah...? I understand that structs are value types, but does this mean that the values within the struct can be changed while the values the struct points to can't be? And this differs from a class because a class is a reference type by default...? So, wait, struct Foo { int x; } class Bar { int x; } const(Foo) foo; const(Bar) bar = new Bar(); foo.x = 5; // Ok...? bar.x = 5; // Compile-time error...? Weird. I've always just used structs as stack-allocated classes without inheritence, constructors, or the overhead. Now there's another difference to worry about, I guess because they're value types...
 static if(is(invariant(S*) == invariant(S)*))
 does not pass, but
 invariant(S*) barptr2 = &bar;
 static if(is(typeof(barptr2) == invariant(S)*))
 passes... is there a logical explanation for that?

Now I'm even more confused... I'm from a Java background, so I don't really understand constness already, and the implementation here seems to be way weird... Anyways, thanks all... I guess I'll wait until the implementation matches the docs and there's a tutorial or something out there which explains this all without bringing up a lot of gray areas.

Does this help? It was written before the release of D 2.0, but it does try to explain the difference between the different kinds of const: http://while-nan.blogspot.com/2007/06/you-cant-touch-this.html As for the second thing, I'm not entirely sure either, but given that invariant(char)[] seems to have the behaviour one would expect from invariant(char[]), it could be that there's simply no difference and invariant(char)[] is the canonical form in the compiler. -- Daniel

Jun 20 2007
prev sibling parent Daniel919 <Daniel919 web.de> writes:
 For example, what do these do differently?

 invariant int foo;
 invariant(int) foo;

There is a big difference. invariant(int) foo; 1. the data of foo is an invariant int. 2. the brackets mean: you can assign another int to foo. You can't change the data of foo. But you are allowed to assign an other int to foo. So this doesn't make sense for a simple storage type like int. (for classes this is useful) invariant int foo; 1. the data of foo is an invariant int. 2. the reference of foo is invariant, too So you can't change the data of foo and you can't assign an other int to foo. And this makes sense ;) (for classes this isn't possible, since they can't be assigned at compile-time) If you want the same thing for a class, you have to write: final invariant(MyClass) foo = cast(invariant) new MyClass("mydata"); invariant(MyClass) foo; You can't change the data of foo (like: foo.x=10;). But you could assign an other MyClass to foo (like: foo = cast(invariant) new MyClass("an other MyClass");) final forbids the last step. It means that you can't assign an other MyClass to foo. This is equivalent: "final invariant(int)" and "invariant int". It also shows the need for having 3 different keywords. Even with explicit casting a class can't be assigned at compile-time: invariant MyClass foo = cast(invariant) new MyClass("data"); //Error: non-constant expression cast(invariant MyClass)new MyClass invariant(MyClass) foo = cast(invariant) new MyClass("data"); This is ok, but an other MyClass could be assigned to foo. So we mark it as final: final invariant(MyClass) foo = cast(invariant) new MyClass("data"); and get the same behavior as if we had: invariant MyClass foo = cast(invariant) new MyClass("data"); //Error: non-constant expression cast(invariant MyClass)new MyClass Just to mention it: const creates a read-only access to sth that might be mutable. invariant(MyClass*) ptr = ... //the data of MyClass will never ever change const(MyClass*) ptr = ... //you can't use ptr to change the data, ptr is pointing to Please correct me, if I was wrong with anything. Best regards, Daniel
Jun 19 2007