Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 01, 2008 about the new const regime | ||||
---|---|---|---|---|
| ||||
(dmd 2.009) What's the difference between "const T" and "invariant T", if T is a value type (builtin type or struct)? Value types are always a copy and never refer to anything. So a const(T) can't be changed. Example: typeid(string) == "invariant(char)[]" (default) string s = "bla"; s[0] = 'x'; //Error, cannot change a invariant(char) But then, where is the difference to const(char)? If there really is no difference, shouldn't string be "const(char)[]" then? And maybe invariant(T) should be an error, when T is a valuetype? About enum: Instead of the current "abuse" of enum to also define values that take no space, I would like a new keyword, which can be used more general: meta metaprogramming <=> compile time programming meta <=> compile time meta x = 1; <=> meta int x = 1; x is a compile time value of type int. enum { red, green, blue } //<=> meta red = 0, green = 1, blue = 2; This could also help to make a better distinction: class Foo { static int x; } means x is not bound to an object. using static this(), x can be assigned at runtime static if( ... ) ... means evaluate the if at compile time With the new keyword, it could be renamed to meta if( ... ) ... static <=> not bound to an object meta <=> compile time Best regards and happy new year, Daniel |
January 01, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel919 | On 1/1/08, Daniel919 <Daniel919@web.de> wrote: > (dmd 2.009) > > What's the difference between "const T" and "invariant T", if T is a value type (builtin type or struct)? Pretty much none. In both cases, the type is invariant in practice. > If there really is no difference, shouldn't string be "const(char)[]" > then? And maybe invariant(T) should be an error, when T is a valuetype? You can do const x = 5; invariant x = 5; If the compiler is smart enough, in both cases, x will have type invariant(int). If the compiler doesn't try to be smart, then x will have type const(int) and invariant(int) respectively. Having two ways to say the same thing may seem redundant, but for reasons of generic programming, neither of them should be considered an error. > enum { red, green, blue } //<=> > meta red = 0, green = 1, blue = 2; For those of us who support "real enums", those two are not equivalent, since "real enums" make no numerical value available to the programmer. You have no choice /but/ to use the enumerated names. But of course, for that very reason, many (myself included) have argued that a different keyword for manifest constants would be a good idea (possibly paving the way for "enum" to be retooled to make "real enums" in the future). "meta" is as good a name as any, although I think I like "manifest" better. I'd be happy with either. But right now, neither is on the table. |
January 02, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel919 | 在 Wed, 02 Jan 2008 01:14:22 +0800,Daniel919 <Daniel919@web.de> 写道: > (dmd 2.009) > > What's the difference between "const T" and "invariant T", if T is a value type (builtin type or struct)? > > Value types are always a copy and never refer to anything. > So a const(T) can't be changed. > > Example: > typeid(string) == "invariant(char)[]" (default) > > string s = "bla"; > s[0] = 'x'; //Error, cannot change a invariant(char) > But then, where is the difference to const(char)? > The difference is : string s = "bla"; s = "abc"; // compile, you can reassign to an invariant array with another invariant array, but you can't change it partially. s[0] = 'x'; //error as you said > If there really is no difference, shouldn't string be "const(char)[]" then? And maybe invariant(T) should be an error, when T is a valuetype? > > > About enum: > Instead of the current "abuse" of enum to also define values that take no space, I would like a new keyword, which can be used more general: > > meta > > metaprogramming <=> compile time programming > meta <=> compile time > > meta x = 1; <=> meta int x = 1; > x is a compile time value of type int. > > enum { red, green, blue } //<=> > meta red = 0, green = 1, blue = 2; > > > This could also help to make a better distinction: > class Foo { static int x; } > means x is not bound to an object. using static this(), x can be assigned at runtime > > static if( ... ) ... > means evaluate the if at compile time > > With the new keyword, it could be renamed to > meta if( ... ) ... > > static <=> not bound to an object > meta <=> compile time > > > Best regards and happy new year, > Daniel -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/ |
January 02, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to davidl | > The difference is :
>
> string s = "bla";
> s = "abc"; // compile, you can reassign to an invariant array with another invariant array, but you can't change it partially.
> s[0] = 'x'; //error as you said
But the same is true for a const(char)[].
const(char)[] s = "bla";
s = "abc";
s[0] = 'x'; //error
const char[] s = "bla";
s = "abc" //error
invariant char[] s = "bla";
s = "abc" //error
|
January 02, 2008 const=readonly invariant=const | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel919 | > What's the difference between "const T" and "invariant T", if T is a value type (builtin type or struct)? > > Value types are always a copy and never refer to anything. > So a const(T) can't be changed. There is a little difference: struct St { T ptr2sth; } //T is a class or a pointer to sth const St st = St(&sth); st.ptr2sth is an invariant ptr to: sth that might change invariant St st = St(&someobj); st.ptr2sth is an invariant ptr to: sth that will never change However, const(valuetype) is always equivalent to invariant(valuetype) That's also why: const Foo* ptr2foo; a const ptr to a const Foo <=> an invariant ptr to a const Foo So the distinction between const and invariant is only important, when it comes to the question, what a ptr is pointing to: 1. const(Foo)* ptr2constfoo = &foo; 2. invariant(Foo)* ptr2invariantfoo = &foo; My opinion is that const reads like: this will never change I know there is no difference between const,invariant,readonly,immutable,... in the English language. And that in C++ const also doesn't mean "this will never change". But I think, the best fitting one to express what we really want in case 1 is: readonly Because it stands for what we intend to do: Use this ptr to read Foo only. So a ptr to sth readonly means: readonlyview AND NOT: ptr to readonly data (just like function params in,inout,out express what we intend to do) Of course one could argue that readonly reads like: this Foo is readonly and thus will never change. But for const it's the other way round: I argue that const reads like: this Foo is const and thus will never change And not that it means: we can only read this Foo from this ptr (but it might get changed from somewhere) It's the problem that all these words are synonyms in the English language. But I can better live with: readonly(T)* to mean: ptr that is used to read only and NOT to mean: ptr to sth that will never change than const(T)* to mean: ptr that is used to read only and NOT to mean: ptr to sth that will never change This way const T foo = ...; would mean that nothing of foo will ever change. With the current system, you would have to use invariant. But then, for consistency, you should not use "const x = 1;" but "invariant x = 1;" So you would mostly use invariant, and const only where you want to say: ptr that is used to read only But then it would be easier if we change: const to readonly invariant to const You can give it a try, just compile like: cat ./test.d | sed -e 's/const/invariant/g;s/readonly/const/g' > test2.d && dmd.exe test2.d | sed -e 's/const/readonly/g;s/invariant/const/g' && ./test2 Best regards, Daniel |
January 02, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel919 | "Daniel919" wrote
>> The difference is :
>>
>> string s = "bla";
>> s = "abc"; // compile, you can reassign to an invariant array with
>> another invariant array, but you can't change it partially.
>> s[0] = 'x'; //error as you said
>
> But the same is true for a const(char)[].
> const(char)[] s = "bla";
> s = "abc";
> s[0] = 'x'; //error
>
> const char[] s = "bla";
> s = "abc" //error
>
> invariant char[] s = "bla";
> s = "abc" //error
The difference is subtle. invariant means "nothing can change this". const means "I can't change this".
So for a const array, for instance:
char[] s = "bla".dup;
const(char)[] c = s; // ok
invariant(char)[] i = s; // error
invariant(char)[] i2 = c; // error
This is an error because since you could potentially change i by changing s, you can't assign s to i or c to i without an explicit cast. The explicit cast tells the compiler you are ensuring that s will no longer be changed by anything:
invariant(char)[] i3 = cast(invariant(char)[])s; // ok
This is ok, but you can no longer change s. If you do, the behavior is undefined.
Do you see the difference now? In most cases, if you are initializing a const variable with a literal, or a new() statement, you can change the modifier to invariant because logically, nothing can change that variable. It would be nice if the compiler automatically did this for you, but I don't think this is the case today.
-Steve
|
January 02, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | > The difference is subtle. invariant means "nothing can change this". const means "I can't change this". .. from this pointer/ref. So I can read this only from this pointer/ref. Ok, I already posted some thoughts about it under this topic. > So for a const array, for instance: > > char[] s = "bla".dup; > const(char)[] c = s; // ok > invariant(char)[] i = s; // error > invariant(char)[] i2 = c; // error > > This is an error because since you could potentially change i by changing s, Tried it: char[] s = "bla".dup; const(char)[] c = s; writefln( c ); //bla s = "new".dup; writefln( c ); //bla So c got a copy of s. But then, how can I change c by using s? If I can't, then I see no difference to invariant(char)[]. If c was a reference to s, then it would make sense to distinct between: 1. can't change the data of c via c = const(char)[] 2. data of c will never change = invariant(char)[] > you can't assign s to i or c to i without an explicit cast. The explicit cast tells the compiler you are ensuring that s will no longer be changed by anything: > > invariant(char)[] i3 = cast(invariant(char)[])s; // ok > > This is ok, but you can no longer change s. If you do, the behavior is undefined. > > Do you see the difference now? In most cases, if you are initializing a const variable with a literal, or a new() statement, you can change the modifier to invariant because logically, nothing can change that variable. It would be nice if the compiler automatically did this for you, but I don't think this is the case today. > > -Steve > > |
January 02, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel919 | "Daniel919" wrote
>> So for a const array, for instance:
>>
>> char[] s = "bla".dup;
>> const(char)[] c = s; // ok
>> invariant(char)[] i = s; // error
>> invariant(char)[] i2 = c; // error
>>
>> This is an error because since you could potentially change i by changing s,
> Tried it:
> char[] s = "bla".dup;
> const(char)[] c = s;
> writefln( c ); //bla
> s = "new".dup;
> writefln( c ); //bla
> So c got a copy of s. But then, how can I change c by using s?
> If I can't, then I see no difference to invariant(char)[].
> If c was a reference to s, then it would make sense to distinct between:
> 1. can't change the data of c via c = const(char)[]
> 2. data of c will never change = invariant(char)[]
c is not a copy of s or a reference to s. c references the same data that s references. When you change s to reference different data, it does not change c to reference this data. i.e. after the assignment, s.ptr != c.ptr. Maybe this example will help:
int x = 5;
int *p = &x;
int *p2 = p;
writefln(*p, *p2); // outputs 55
int y = 6;
p = &y;
writefln(*p, *p2); // outputs 65
Assigning p to &y is similar to your code assigning s to "new".dup;
Now, if you modified a piece of the data s is pointing to, then c will change. Try this:
s[0..3] = "new";
This copies the data from the array on the right into the array on the left
(I didn't yet compile this, so I'm not sure if it compiles as coded).
-Steve
|
January 02, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | > c is not a copy of s or a reference to s. c references the same data that s references. When you change s to reference different data, it does not change c to reference this data. i.e. after the assignment, s.ptr != c.ptr. Maybe this example will help:
>
> int x = 5;
> int *p = &x;
> int *p2 = p;
> writefln(*p, *p2); // outputs 55
>
> int y = 6;
> p = &y;
>
> writefln(*p, *p2); // outputs 65
>
> Assigning p to &y is similar to your code assigning s to "new".dup;
>
> Now, if you modified a piece of the data s is pointing to, then c will change. Try this:
>
> s[0..3] = "new";
> This copies the data from the array on the right into the array on the left (I didn't yet compile this, so I'm not sure if it compiles as coded).
writefln( c ); //test
s[0..3] = "new";
writefln( c ); //newt
This made it clear, shows that c is not a copy of s.
And as expected:
c[0..3] = "new";//Error: slice c[cast(uint)0..cast(uint)3] is not mutable
const(char)[] c = s;
elements c refers to can't be changed via c
invariant(char)[] i = s;
elements i refers to will never change
Thanks for your explanation.
|
January 02, 2008 Re: about the new const regime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Steven Schveighoffer Wrote:
> "Daniel919" wrote
> > const char[] s = "bla";
> > s = "abc" //error
> >
> > invariant char[] s = "bla";
> > s = "abc" //error
>
> The difference is subtle. invariant means "nothing can change this". const means "I can't change this".
The difference being that the compiler is allowed to optimize an invariant under the assumption that it won't ever *be* changed may entail caching results of evaluating it, and other similar optimizations.
Lemma 1) accepting that our algorithms are incorrect if changed by influences outside our control.
This lemma is inherent to all programs though. One cannot control the environment on which they run. Sure, we can perform sanity checks, but even bootloaders and OS's are run on emulators and can be influenced in unexpected ways. I would therefore suggest that everything that is const within an entire program is therefore inherently invariant for our purposes.
Regards,
Dan
|
Copyright © 1999-2021 by the D Language Foundation