Jump to page: 1 2
Thread overview
about the new const regime
Jan 01, 2008
Daniel919
Jan 01, 2008
Janice Caron
Jan 02, 2008
davidl
Jan 02, 2008
Daniel919
Jan 02, 2008
Daniel919
Jan 02, 2008
Daniel919
Jan 02, 2008
Dan
const=readonly invariant=const
Jan 02, 2008
Daniel919
Jan 02, 2008
Bruce Adams
Jan 04, 2008
Oskar Linde
Jan 04, 2008
Sascha Katzner
January 01, 2008
(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
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
在 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
> 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
> 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
"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
> 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
"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
> 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
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
« First   ‹ Prev
1 2