| Thread overview | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 28, 2009 immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
I am about one year late for such comments or more. I also have some suggestions and questions. I suggest to perform a serch & replace in all the D2 documentation to replace all "invariant" with "immutable". Some versions of D2 from now "invariant" can be removed from DMD itself. ----------------- From the examples of the docs. I hope to not see this code, it's not easy to understand: immutable(char*)** p = ...; ----------------- >The const and immutable function attributes can also appear after the closing parenthesis of the parameter list: < I think this doesn't produce much damage, but why? ----------------- Mutable and transitive-immutable data types are easy to understand. But "const" is less easy to understand for me: >Const types are like immutable types, except that const forms a read-only view of data. Other aliases to that same data may change it at any time.< Regarding its purpose the docs say just: >const finds applications in passing data through interfaces that promise not to modify them.< I suggest to add more examples of "const" usage, to show where it can be useful, because I am not much able to understand where to use it. It may also be better to rename "const" of D2 as "constview" or "cview" then (and the meaning of const can be kept from D1). The semantic overloading of the "enum" keyword doesn't look nice, but it's not too much bad. ----------------- The following things are written about constview/immutable member functions: immutable member functions are guaranteed that the object and anything referred to by the this reference is immutable. They are declared as: struct S { int x; immutable void foo() { x = 4; // error, x is immutable this.x = 4; // error, x is immutable } } constview member functions are functions that are not allowed to change any part of the object through the member function's this reference. I don't understand such explanations, and I'd like to see a bit wider example(s) about it. ----------------- Immutable structs/classes can be quite useful, they are safer, remove some complexity from a program, they can be sometimes the right thing you want (think about a Date object that keeps one day of the year), help paralellism, and they may allow for other optimizations (for example there's no need to copy them (so you can save memory and/or allocations, just like for immutable strings), or on the opposite you can have a copy of them on each CPU cache, and you are sure they will not go out of sync, this allows for a program more scalable on multi-cores). So I have tried to write a very simple program that uses immutable structs and classes: immutable struct S { int x; this(int xx) { this.x = x; } } immutable class C { int x; this(int xx) { this.x = x; } } void main() { auto s = S(10); auto c = new C(10); } But the compiler outputs: Error: cannot implicitly convert expression (this) of type immutable(C) to test.C test.d(8): Error: constructor test.C.this missing initializer for final field x test.d(12): Error: constructor test.S.this (int xx) does not match parameter types (int) test.d(12): Error: ((immutable immutable(S) __ctmp1 = 0; ) , __ctmp1).this can only be called on a mutable object, not immutable(S) I don't understand such errors much. What is that I am doing wrong? Note that if you remove the "immutable" that program works, and if you replace "immutable" with "invariant" the compiler gives thye same errors (internally it keeps using immutable(C)). Thank you, bye, bearophile | ||||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile Wrote:
> I am about one year late for such comments or more. I also have some suggestions and questions.
>
> I suggest to perform a serch & replace in all the D2 documentation to replace all "invariant" with "immutable". Some versions of D2 from now "invariant" can be removed from DMD itself.
>
> -----------------
>
> From the examples of the docs. I hope to not see this code, it's not easy to understand: immutable(char*)** p = ...;
>
> -----------------
>
> >The const and immutable function attributes can also appear after the closing parenthesis of the parameter list: <
>
> I think this doesn't produce much damage, but why?
>
> -----------------
>
> Mutable and transitive-immutable data types are easy to understand. But "const" is less easy to understand for me:
>
> >Const types are like immutable types, except that const forms a read-only view of data. Other aliases to that same data may change it at any time.<
>
> Regarding its purpose the docs say just:
>
> >const finds applications in passing data through interfaces that promise not to modify them.<
>
> I suggest to add more examples of "const" usage, to show where it can be useful, because I am not much able to understand where to use it.
>
> It may also be better to rename "const" of D2 as "constview" or "cview" then (and the meaning of const can be kept from D1).
>
> The semantic overloading of the "enum" keyword doesn't look nice, but it's not too much bad.
>
> -----------------
>
> The following things are written about constview/immutable member functions:
>
> immutable member functions are guaranteed that the object and anything referred to by the this reference is immutable. They are declared as:
>
> struct S {
> int x;
>
> immutable void foo() {
> x = 4; // error, x is immutable
> this.x = 4; // error, x is immutable
> }
> }
>
> constview member functions are functions that are not allowed to change any part of the object through the member function's this reference.
>
> I don't understand such explanations, and I'd like to see a bit wider example(s) about it.
>
> -----------------
>
> Immutable structs/classes can be quite useful, they are safer, remove some complexity from a program, they can be sometimes the right thing you want (think about a Date object that keeps one day of the year), help paralellism, and they may allow for other optimizations (for example there's no need to copy them (so you can save memory and/or allocations, just like for immutable strings), or on the opposite you can have a copy of them on each CPU cache, and you are sure they will not go out of sync, this allows for a program more scalable on multi-cores).
>
> So I have tried to write a very simple program that uses immutable structs and classes:
>
> immutable struct S {
> int x;
> this(int xx) { this.x = x; }
> }
>
> immutable class C {
> int x;
> this(int xx) { this.x = x; }
> }
>
> void main() {
> auto s = S(10);
> auto c = new C(10);
> }
>
>
> But the compiler outputs:
>
>
> Error: cannot implicitly convert expression (this) of type immutable(C) to test.C
> test.d(8): Error: constructor test.C.this missing initializer for final field x
> test.d(12): Error: constructor test.S.this (int xx) does not match parameter types (int)
> test.d(12): Error: ((immutable immutable(S) __ctmp1 = 0;
>
> ) , __ctmp1).this can only be called on a mutable object, not immutable(S)
>
>
> I don't understand such errors much. What is that I am doing wrong?
> Note that if you remove the "immutable" that program works, and if you replace "immutable" with "invariant" the compiler gives thye same errors (internally it keeps using immutable(C)).
>
> Thank you,
> bye,
> bearophile
Well, I'm glad it's just not me! Anytime I've used the keyword 'invariant' what I get just won't compile. So I remove it, which suggests that from a practical point of view, it is not much use.
Const for me should mean pretty much what it means in C++
If I write:
foo(const Bar b)
{
// I mean that if in my implementation of the function, I try to alter
// b, then the compiler should flag it as an error.
}
foo(invariant Bar b)
{
// Does not seem to offer anything else that I need!
}
| |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Tue, 28 Apr 2009 13:43:48 -0400, bearophile <bearophileHUGS@lycos.com> wrote: >> The const and immutable function attributes can also appear after the closing parenthesis of the parameter list: < > > I think this doesn't produce much damage, but why? First, C++ does it this way: int foo() const { } Second, because const/immutable is a type constructor, it can be applied to the return type as well as the function. So what looks less confusing to you: const A foo() // const function which returns a mutable A A foo() const // same thing, clearly const can't apply to A const const A foo() // const function which returns a const A const A foo() const // ditto There have been proposals to change const to const(this), so it is clear what you are applying const to (in fact, that is what a const function does, just mark the hidden "this" parameter as const): const(this) A foo() const A foo() // would either be syntax error or mean a normal fn that returns a const A I'd be in favor of such a change. > ----------------- > > The following things are written about constview/immutable member functions: > > immutable member functions are guaranteed that the object and anything referred to by the this reference is immutable. They are declared as: > > struct S { > int x; > > immutable void foo() { > x = 4; // error, x is immutable > this.x = 4; // error, x is immutable > } > } > > constview member functions are functions that are not allowed to change any part of the object through the member function's this reference. > > I don't understand such explanations, and I'd like to see a bit wider example(s) about it. The detail you are missing is that anything is implicitly castable to const, but nothing else implicitly casts. Think about it this way: const means "I cannot change this, but something else might be able to." So mutable can implicitly be cast to const if I don't want to change it, and immutable can implicitly cast to const. Mutable and immutable cannot implicitly be cast to eachother because that would violate immutability. So since something that is const could potentially be immutable OR mutable, it can't be implicitly cast to immutable or mutable because that would violate immutability. Many functions want the contract "I won't change this, but I don't care what anybody else does to it", so those are perfect candidates for const. The benefit is you can pass in mutable, const, or immutable data without an explicit cast. Immutable functions can add extra optimizations to their code. For example, you don't need to lock an immutable object to access its data. This kind of thing is very important for statically provable purity. > > ----------------- > > Immutable structs/classes can be quite useful, they are safer, remove some complexity from a program, they can be sometimes the right thing you want (think about a Date object that keeps one day of the year), help paralellism, and they may allow for other optimizations (for example there's no need to copy them (so you can save memory and/or allocations, just like for immutable strings), or on the opposite you can have a copy of them on each CPU cache, and you are sure they will not go out of sync, this allows for a program more scalable on multi-cores). > > So I have tried to write a very simple program that uses immutable structs and classes: > > immutable struct S { > int x; > this(int xx) { this.x = x; } > } > > immutable class C { > int x; > this(int xx) { this.x = x; } > } > > void main() { > auto s = S(10); > auto c = new C(10); > } > > > But the compiler outputs: > > > Error: cannot implicitly convert expression (this) of type immutable(C) to test.C > test.d(8): Error: constructor test.C.this missing initializer for final field x > test.d(12): Error: constructor test.S.this (int xx) does not match parameter types (int) > test.d(12): Error: ((immutable immutable(S) __ctmp1 = 0; > > ) , __ctmp1).this can only be called on a mutable object, not immutable(S) > > > I don't understand such errors much. What is that I am doing wrong? > Note that if you remove the "immutable" that program works, and if you replace "immutable" with "invariant" the compiler gives thye same errors (internally it keeps using immutable(C)). > Unfortunately, the whole thing is not completely fleshed out. currently, the only way to make an immutable class instance is to make a mutable class instance, and cast it to immutable once you have constructed it. Therefore, saying all instances of a class are immutable renders it useless. I don't really like the way this works, as the compiler is depending on the developer to ensure something marked as immutable really doesn't have any other mutable references to it. This can be difficult if you don't know the contents of the class. -Steve | |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | > immutable struct S {
> int x;
> this(int xx) { this.x = x; }
> }
As far as I know, immutable has no effect on class declarations, so what your code says is
struct S {
immutable int x;
this(int xx) immutable { this.x = x; }
}
and that's causing problems. If you want an immutable instance, you can say:
auto c = new immutable(C)(10);
or cast an existing instance to immutable.
| |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Christian Kamm | On Tue, Apr 28, 2009 at 5:17 PM, Christian Kamm <kamm-incasoftware@removethis.de> wrote: > As far as I know, immutable has no effect on class declarations It does. http://www.digitalmars.com/d/2.0/class.html At the very bottom it describes const and invariant (i.e. immutable) classes. | |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Christian Kamm | Many thanks Steven Schveighoffer for the good explanations. Now I think I have understood what's one of the purposes of const. const arguments of a function just states that you aren't going to change the data inside a function/method, more or less like in C++, but in a transitive way.
But wasn't "in" before an argument type already doing that? I presume "in" isn't transitive. I have tried this:
import std.stdio: writeln;
void foo(in int* x) {
(*x) = (*x) * 10;
writeln(*x);
}
void main() {
int y = 10;
foo(&y);
}
But it doesn't work, so maybe in and const are the same thing now. Is "in" going to be removed then? Or maybe it's better to remove const and keep just a transitive "in". And I have seen "immutable ref" too is allowed, I guess it's mostly for performance reasons. Maybe "immutable in" is just for show, this works:
import std.stdio: writeln;
void foo(immutable in int x) {
writeln(x * 2);
}
void main() {
int y = 10;
foo(y);
}
I want a simpler language -.-
While this doesn't work:
import std.stdio: writeln;
void foo(const in int x) {
writeln(x * 2);
}
void main() {
int y = 10;
foo(y);
}
it prints: "redundant storage class in". So const and "in" seem really the same thing. But then what does it mean "immutable in"? I guess it just means transitive-immutable.
"immutable out" and "const out" are thankfully disallowed. So I guess "in" is now deprecated, it's just an alias of "const. But this idea seems wrong because "in ref" is disalloed but "const ref" is allowed, so they aren't just an alias of each other.
So the available ones are ("in" not listed to keep a bit of my sanity):
immutable type
const type
out type
immutable ref type
const ref type
type
type*
type**
etc
-----------------------------
Christian Kamm:
> > immutable struct S {
> > int x;
> > this(int xx) { this.x = x; }
> > }
>
> As far as I know, immutable has no effect on class declarations, so what your code says is
>
> struct S {
> immutable int x;
> this(int xx) immutable { this.x = x; }
> }
>
> and that's causing problems. If you want an immutable instance, you can say:
>
> auto c = new immutable(C)(10);
Sorry, the constructor was:
this(int xx) { this.x = xx; }
The following code works, and x can't be modified from outside the constructor:
import std.stdio: writeln;
immutable struct S {
int x;
this(int xx) { this.x = xx * 2; }
}
void main() {
auto s = new S(10);
writeln(s.x); // 20
}
I think it works because s is a mutable pointer to an immutable struct.
If you do this:
auto s = S(10);
The assignment doesn't work because s too is immutable.
Well, this idea may be false because a line of code just like this doesn't work:
S(10);
I don't see ways yet to create an immutable struct on the stack.
Well... you can do:
S s = { 10 };
But then the constructor isn't called.
The following too works:
import std.stdio: writeln;
struct S {
int x;
this(int xx) { this.x = xx * 2; }
}
void main() {
auto s = new immutable(S)(10);
writeln(s.x);
}
I don't repeat similar experiments with immutable classes because they seem to never work to me.
I think I have already understood about 5% of this topic :-)
Bye,
bearophile
| |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steve Teale | On Tue, 28 Apr 2009 14:08:58 -0400, Steve Teale wrote: > bearophile Wrote: > >> I am about one year late for such comments or more. I also have some suggestions and questions. >> >> I suggest to perform a serch & replace in all the D2 documentation to replace all "invariant" with "immutable". Some versions of D2 from now "invariant" can be removed from DMD itself. >> >> ----------------- >> >> From the examples of the docs. I hope to not see this code, it's not easy to understand: immutable(char*)** p = ...; >> >> ----------------- >> >>>The const and immutable function attributes can also appear after the closing parenthesis of the parameter list: < >> >> I think this doesn't produce much damage, but why? >> >> ----------------- >> >> Mutable and transitive-immutable data types are easy to understand. But "const" is less easy to understand for me: >> >>>Const types are like immutable types, except that const forms a read-only view of data. Other aliases to that same data may change it at any time.< >> >> Regarding its purpose the docs say just: >> >>>const finds applications in passing data through interfaces that promise not to modify them.< >> >> I suggest to add more examples of "const" usage, to show where it can be useful, because I am not much able to understand where to use it. >> >> It may also be better to rename "const" of D2 as "constview" or "cview" then (and the meaning of const can be kept from D1). >> >> The semantic overloading of the "enum" keyword doesn't look nice, but it's not too much bad. >> >> ----------------- >> >> The following things are written about constview/immutable member functions: >> >> immutable member functions are guaranteed that the object and anything referred to by the this reference is immutable. They are declared as: >> >> struct S { >> int x; >> >> immutable void foo() { >> x = 4; // error, x is immutable >> this.x = 4; // error, x is immutable >> } >> } >> >> constview member functions are functions that are not allowed to change any part of the object through the member function's this reference. >> >> I don't understand such explanations, and I'd like to see a bit wider example(s) about it. >> >> ----------------- >> >> Immutable structs/classes can be quite useful, they are safer, remove some complexity from a program, they can be sometimes the right thing you want (think about a Date object that keeps one day of the year), help paralellism, and they may allow for other optimizations (for example there's no need to copy them (so you can save memory and/or allocations, just like for immutable strings), or on the opposite you can have a copy of them on each CPU cache, and you are sure they will not go out of sync, this allows for a program more scalable on multi-cores). >> >> So I have tried to write a very simple program that uses immutable structs and classes: >> >> immutable struct S { >> int x; >> this(int xx) { this.x = x; } >> } >> >> immutable class C { >> int x; >> this(int xx) { this.x = x; } >> } >> >> void main() { >> auto s = S(10); >> auto c = new C(10); >> } >> >> But the compiler outputs: >> >> Error: cannot implicitly convert expression (this) of type immutable(C) to test.C >> test.d(8): Error: constructor test.C.this missing initializer for final field x >> test.d(12): Error: constructor test.S.this (int xx) does not match parameter types (int) >> test.d(12): Error: ((immutable immutable(S) __ctmp1 = 0; >> >> ) , __ctmp1).this can only be called on a mutable object, not immutable(S) >> >> I don't understand such errors much. What is that I am doing wrong? >> Note that if you remove the "immutable" that program works, and if you replace "immutable" with "invariant" the compiler gives thye same errors (internally it keeps using immutable(C)). >> >> Thank you, >> bye, >> bearophile > > Well, I'm glad it's just not me! Anytime I've used the keyword 'invariant' what I get just won't compile. So I remove it, which suggests that from a practical point of view, it is not much use. > > Const for me should mean pretty much what it means in C++ > > If I write: > > foo(const Bar b) > { > // I mean that if in my implementation of the function, I try to alter > // b, then the compiler should flag it as an error. > } > > foo(invariant Bar b) > { > // Does not seem to offer anything else that I need! > } The difference between immutable and const, in my understanding, is that 'immutable' means that nothing in the program will change it, and 'const' means that this function won't change it but it might be changed by other functions in the program. What has surprised me is that immutability is *not* guaranteed. It is also just a promise that the coder makes to the compiler. You can declare something as immutable and have the program change it. The compiler does not actually prevent that happening, it only makes it difficult to do. Same with const. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell | |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile Wrote: > Many thanks Steven Schveighoffer for the good explanations. Now I think I have understood what's one of the purposes of const. const arguments of a function just states that you aren't going to change the data inside a function/method, more or less like in C++, but in a transitive way. > <snip> > But it doesn't work, so maybe in and const are the same thing now. Is "in" going to be removed then? Or maybe it's better to remove const and keep just a transitive "in". And I have seen "immutable ref" too is allowed, I guess it's mostly for performance reasons. Maybe "immutable in" is just for show, this works: > > So the available ones are ("in" not listed to keep a bit of my sanity): > immutable type > const type > out type > immutable ref type > const ref type > type > type* > type** > etc > On the language/functions page: "The in storage class is equivalent to const scope." I hope that clears everything up for you! :-) Paul | |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Derek Parnell | Reply to Derek,
> What has surprised me is that immutability is *not* guaranteed. It is
> also just a promise that the coder makes to the compiler. You can
> declare something as immutable and have the program change it. The
> compiler does not actually prevent that happening, it only makes it
> difficult to do. Same with const.
>
The language has asm blocks can can call C. The only things it can guarantee are the same things the OS can guarantee.
If the the language can get at sprintf and sscanf, you can get around any const system ever made.
| |||
April 28, 2009 Re: immutable, const, enum | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile Wrote:
<snip>
> it prints: "redundant storage class in". So const and "in" seem really the same thing. But then what does it mean "immutable in"? I guess it just means transitive-immutable.
>
> "immutable out" and "const out" are thankfully disallowed. So I guess "in" is now deprecated, it's just an alias of "const. But this idea seems wrong because "in ref" is disalloed but "const ref" is allowed, so they aren't just an alias of each other.
>
> So the available ones are ("in" not listed to keep a bit of my sanity):
> immutable type
> const type
> out type
> immutable ref type
> const ref type
> type
> type*
> type**
> etc
>
<snip>
From the D2.0/Language/Functions page, under Function Parameters:
"The in storage class is equivalent to const scope."
That's why the "const in" combination doesn't work.
Paul
"I can't tell a lie -- not even when I hear one."
John Kendrik Bangs, A House-Boat on the Styx.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply