www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - a more consistent const syntax

reply Daniel919 <Daniel919 web.de> writes:
I've got some ideas about how to make the const syntax more
consistent.
First I will show you the current situation.
Then I will list the confusions and possible solutions.

Some days ago I already mentioned my first idea on IRC, but got no replies.
Also I know that you, Walter, hardly don't change features, which
already have been implemented.
And my suggestions would require this of course.

The "define proposal" is not such a big change in the language,
in opposite to the much more important idea about
"putting the return type in a bracket at the end".
Because this is what the last idea requires, it's written after "WAIT:".

Nevertheless I will give it a try, because 2.0 is still alpha and it 
will break code compatibility anyway.



currently the keyword const(/invariant) has three meanings:
-----------------------------------------------------------
1. alone: const x = 1; compile-time variable (not an lvalue)
2. with(): const(P) p = new Point(1,2); run-time object, which is 
protected from changes
3. alone: const P func(P p) { writefln(p.x, " ", p.y); }; attribute for 
a member function: the function can't change any class fields


confusions and solutions:
-------------------------
#1
1. const x = 1;
2. const(P) p = new Point(1,2);
you see const first and later recognize the brackets
one would not expect brackets to lead to a completely different meaning 
of the forrun keyword

1. define x = 1;
2. const(P) p = new Point(1,2);
can't be confused anymore, different keywords
define defines a compile-time variable
const / invariant has nothing to do with compile-time anymore. it only 
means protection


#2
3. const P func(P p) { ... }
reads like: func returns a const(P)

const / invariant alone (without brackets) is an attribute and has no 
other meaning
further proposal: returned types in a bracket at the end:
3. const func (P p) (P) { ... }
//templated syntax: const func!(T) (T p) (T) { ... }


#3
1. same meaning: invariant x = 1; const x = 1;

not allowed anymore: const(/invariant) alone is an attribute, instead use:
1. define x = 1;


#4
//this is ok: final int x = 1; const(int)* xptr = &x; // but:
2. const(int) x = 1;
this is nonsense and also atm it could be confused with:
1. const int x = 1;

the compiler should issue at least a warning, and instead you should use:
1. define x = 1;


#5
void func(const P p) { typeof(p) == const(P) }
bad, because one could expect this to be also valid then:
const P p = new P(1,2); //but fails of course
correctly is has to be:
void func(const(P) p) { ... }
void func(ref const(P) p) { p = new P(3,4); } //OK
//void func(const(int) i) { ... } //const(int) nonsense (see #4)
//void func(ref const(int) i) { ... } //const(int) nonsense (see #4)

compiler should issue an error
const(/invariant) alone is an attribute


WAIT:
-----
because we have another syntax for compile-time variables now,
we could say that:
const P** ptr2ptr2P means:
const(P**) ptr2ptr2P
in this case, #5 would be allowed
but this would also require #2 further proposal to be implemented, 
because if it wasn't:
const P** func() { ... }
would not only be confused with, but it would be THE SAME as:
const(P**) func() { ... }
then the correct form would have to be:
const func() (const P**) { ...}

note that #4 would be true for: const int x = 1; then
this would be nonsense, because it would be the same as: const(int) x = 1;
so the compiler should issue at least a warning



PS: Having the return types in a bracket at the end, would make it
possible to implement multiple return values / return tuples
in a consistent way, too.
It would also allow more tricks, like returning local values of a 
function, avoiding ref, etc etc ...



I would really enjoy to get some replies (especially yours, Walter),
even if it's just a: "No that's totally stupid" ;)

Best regards,
Daniel
Aug 05 2007
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Daniel919 wrote:
 I've got some ideas about how to make the const syntax more
 consistent.
 First I will show you the current situation.
 Then I will list the confusions and possible solutions.
 
 Some days ago I already mentioned my first idea on IRC, but got no replies.
 Also I know that you, Walter, hardly don't change features, which
 already have been implemented.
 And my suggestions would require this of course.
 
 The "define proposal" is not such a big change in the language,
 in opposite to the much more important idea about
 "putting the return type in a bracket at the end".
 Because this is what the last idea requires, it's written after "WAIT:".
 
 Nevertheless I will give it a try, because 2.0 is still alpha and it 
 will break code compatibility anyway.
 
 
 
 currently the keyword const(/invariant) has three meanings:
 -----------------------------------------------------------
 1. alone: const x = 1; compile-time variable (not an lvalue)

Well technically if that was what I wanted, I'd use one of 'invariant x = 1;' or a more explicit 'final invariant(int) x = 1;'.
 2. with(): const(P) p = new Point(1,2); run-time object, which is 
 protected from changes

Well, protected from changes via this reference... but yeah. I'd say the 'const(type)' case would/should be used most often anyhow.
 3. alone: const P func(P p) { writefln(p.x, " ", p.y); }; attribute for 
 a member function: the function can't change any class fields

#3 is an issue, in my book. Not a massive one, but its there. We'll get into that one below.
 
 confusions and solutions:
 -------------------------
 #1
 1. const x = 1;
 2. const(P) p = new Point(1,2);
 you see const first and later recognize the brackets
 one would not expect brackets to lead to a completely different meaning 
 of the forrun keyword

My eyes are trained to spot them... still yes, a sudden shift in meaning can be counter-intuitive. Although its not entirely a shift... you could probably think of 'const x = 1;' as shorthand for 'final const(int) x = 1;'.
 1. define x = 1;
 2. const(P) p = new Point(1,2);
 can't be confused anymore, different keywords
 define defines a compile-time variable
 const / invariant has nothing to do with compile-time anymore. it only 
 means protection

Adding new keywords is usually the absolute last option around here. (There was talk ages past of replacing 'auto x = 1' with 'let x = 1'.)
 
 #2
 3. const P func(P p) { ... }
 reads like: func returns a const(P)

Which is, indeed, a problem -- in that I agree.
 const / invariant alone (without brackets) is an attribute and has no 
 other meaning
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. No, seriously, I just could not possibly handle that; I would keep thinking I saw templates where there aren't any. Worse yet, for a long time I'll see the '!(' and keep wondering how I could be instantiating a template in that position, when its really a template declaration. T'is a naughty naughty thing to mix the two -- would give both the compiler and the user headaches. IMHO, its the 'const'/'invariant' keyword on methods that needs to move -- not sure where it should go, though. What looks best down here? ;) (First listing is the current state, for reference.) const P vunc (P p) { ... } P const func (P p) { ... } P const:func (P p) { ... } P const(func) (P p) { ... } P func const (P p) { ... } P func:const (P p) { ... } P func (P p) const { ... }
 
 #3
 1. same meaning: invariant x = 1; const x = 1;

For basic types, there often isn't much difference anyhow. Except that invariant members of structures allocate no memory in the structure, for example.
 not allowed anymore: const(/invariant) alone is an attribute, instead use:
 1. define x = 1;
 
 #4
 //this is ok: final int x = 1; const(int)* xptr = &x; // but:
 2. const(int) x = 1;
 this is nonsense and also atm it could be confused with:
 1. const int x = 1;
 
 the compiler should issue at least a warning, and instead you should use:
 1. define x = 1;
 
 
 #5
 void func(const P p) { typeof(p) == const(P) }
 bad, because one could expect this to be also valid then:
 const P p = new P(1,2); //but fails of course
 correctly is has to be:
 void func(const(P) p) { ... }
 void func(ref const(P) p) { p = new P(3,4); } //OK
 //void func(const(int) i) { ... } //const(int) nonsense (see #4)
 //void func(ref const(int) i) { ... } //const(int) nonsense (see #4)
 
 compiler should issue an error
 const(/invariant) alone is an attribute
 
 
 WAIT:
 -----
 because we have another syntax for compile-time variables now,
 we could say that:
 const P** ptr2ptr2P means:
 const(P**) ptr2ptr2P
 in this case, #5 would be allowed
 but this would also require #2 further proposal to be implemented, 
 because if it wasn't:
 const P** func() { ... }
 would not only be confused with, but it would be THE SAME as:
 const(P**) func() { ... }
 then the correct form would have to be:
 const func() (const P**) { ...}
 
 note that #4 would be true for: const int x = 1; then
 this would be nonsense, because it would be the same as: const(int) x = 1;
 so the compiler should issue at least a warning
 
 
 
 PS: Having the return types in a bracket at the end, would make it
 possible to implement multiple return values / return tuples
 in a consistent way, too.
 It would also allow more tricks, like returning local values of a 
 function, avoiding ref, etc etc ...
 
 
 
 I would really enjoy to get some replies (especially yours, Walter),
 even if it's just a: "No that's totally stupid" ;)
 
 Best regards,
 Daniel

No that's totally stupid. Ahh I'm just kidding. At least you're thinking about the situation and offering suggestions. (And welcome to the tiny militia of 'const R func()' syntax detractors. ;)) The final/const/invariant system needs some good hammering yet -- although its off to a lovely start, danke Walter. -- Chris Nicholson-Sauls
Aug 05 2007
next sibling parent reply "Rioshin an'Harthen" <rharth75 hotmail.com> writes:
"Chris Nicholson-Sauls" <ibisbasenji gmail.com> kirjoitti viestissä 
news:f951kq$2fss$1 digitalmars.com...
 Daniel919 wrote:
 3. const P func(P p) { ... }
 reads like: func returns a const(P)

Which is, indeed, a problem -- in that I agree.

I agree, as well. It reads like returning a const P.
 const / invariant alone (without brackets) is an attribute and has no 
 other meaning
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. No, seriously, I just could not possibly handle that; I would keep thinking I saw templates where there aren't any. Worse yet, for a long time I'll see the '!(' and keep wondering how I could be instantiating a template in that position, when its really a template declaration. T'is a naughty naughty thing to mix the two -- would give both the compiler and the user headaches. IMHO, its the 'const'/'invariant' keyword on methods that needs to move -- not sure where it should go, though. What looks best down here? ;) (First listing is the current state, for reference.) const P vunc (P p) { ... } P const func (P p) { ... } P const:func (P p) { ... } P const(func) (P p) { ... } P func const (P p) { ... } P func:const (P p) { ... } P func (P p) const { ... }

Definitely the last one. It's immediately familiar to anyone with a C++ background, which I guess most of those coming to D has, and which I think are the people Walter is especially targetting. It also has the added bonus of not complicating method declaration grammar too much. Same list, this time a const func returning a const return value: const const(P) func (P p) const(P) const func (P p) const(P) const(func) (P p) const(P) func const (P p) const(P) func:const (P p) const(P) func (P p) const I definitely prefer the last one as the cleanest of these.
Aug 05 2007
parent reply Paul Collier <paching gmail.com> writes:
Rioshin an'Harthen wrote:
 "Chris Nicholson-Sauls" <ibisbasenji gmail.com> kirjoitti viestissä 
 news:f951kq$2fss$1 digitalmars.com...
 Daniel919 wrote:
 3. const P func(P p) { ... }
 reads like: func returns a const(P)

Which is, indeed, a problem -- in that I agree.

I agree, as well. It reads like returning a const P.
 const / invariant alone (without brackets) is an attribute and has no 
 other meaning
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. No, seriously, I just could not possibly handle that; I would keep thinking I saw templates where there aren't any. Worse yet, for a long time I'll see the '!(' and keep wondering how I could be instantiating a template in that position, when its really a template declaration. T'is a naughty naughty thing to mix the two -- would give both the compiler and the user headaches. IMHO, its the 'const'/'invariant' keyword on methods that needs to move -- not sure where it should go, though. What looks best down here? ;) (First listing is the current state, for reference.) const P vunc (P p) { ... } P const func (P p) { ... } P const:func (P p) { ... } P const(func) (P p) { ... } P func const (P p) { ... } P func:const (P p) { ... } P func (P p) const { ... }

Definitely the last one. It's immediately familiar to anyone with a C++ background, which I guess most of those coming to D has, and which I think are the people Walter is especially targetting. It also has the added bonus of not complicating method declaration grammar too much. Same list, this time a const func returning a const return value: const const(P) func (P p) const(P) const func (P p) const(P) const(func) (P p) const(P) func const (P p) const(P) func:const (P p) const(P) func (P p) const I definitely prefer the last one as the cleanest of these.

Just chiming in on a slightly different note... the line that stuck out in both examples for me was actually the const(func) line. That seems really intuitive and consistent with the const syntax elsewhere. I do find the const-on-the-end readable too, but really mostly because of familiarity with C++ ;)
Aug 05 2007
parent reply Reiner Pope <some address.com> writes:
Paul Collier wrote:
 Rioshin an'Harthen wrote:
 "Chris Nicholson-Sauls" <ibisbasenji gmail.com> kirjoitti viestissä 
 news:f951kq$2fss$1 digitalmars.com...
 Daniel919 wrote:
 3. const P func(P p) { ... }
 reads like: func returns a const(P)

Which is, indeed, a problem -- in that I agree.

I agree, as well. It reads like returning a const P.
 const / invariant alone (without brackets) is an attribute and has 
 no other meaning
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. No, seriously, I just could not possibly handle that; I would keep thinking I saw templates where there aren't any. Worse yet, for a long time I'll see the '!(' and keep wondering how I could be instantiating a template in that position, when its really a template declaration. T'is a naughty naughty thing to mix the two -- would give both the compiler and the user headaches. IMHO, its the 'const'/'invariant' keyword on methods that needs to move -- not sure where it should go, though. What looks best down here? ;) (First listing is the current state, for reference.) const P vunc (P p) { ... } P const func (P p) { ... } P const:func (P p) { ... } P const(func) (P p) { ... } P func const (P p) { ... } P func:const (P p) { ... } P func (P p) const { ... }

Definitely the last one. It's immediately familiar to anyone with a C++ background, which I guess most of those coming to D has, and which I think are the people Walter is especially targetting. It also has the added bonus of not complicating method declaration grammar too much. Same list, this time a const func returning a const return value: const const(P) func (P p) const(P) const func (P p) const(P) const(func) (P p) const(P) func const (P p) const(P) func:const (P p) const(P) func (P p) const I definitely prefer the last one as the cleanest of these.

Just chiming in on a slightly different note... the line that stuck out in both examples for me was actually the const(func) line. That seems really intuitive and consistent with the const syntax elsewhere. I do find the const-on-the-end readable too, but really mostly because of familiarity with C++ ;)

Although the idea is nice, I tried it out, and I don't like the look of it: int const(getFoo)() { return foo; } My main objection is that the const() is around getFoo, so you're saying that the function won't change -- but how can it, it's static data. What you really mean when you are saying it's a const function is that the this object is constant. So how about that? const(this) int getFoo() { return foo; } (It's syntactically unambiguous because this is a keyword) -- Reiner
Aug 05 2007
next sibling parent reply Paul Collier <paching gmail.com> writes:
Reiner Pope wrote:
 Paul Collier wrote:
 Rioshin an'Harthen wrote:
 "Chris Nicholson-Sauls" <ibisbasenji gmail.com> kirjoitti viestissä 
 news:f951kq$2fss$1 digitalmars.com...
 Daniel919 wrote:
 3. const P func(P p) { ... }
 reads like: func returns a const(P)

Which is, indeed, a problem -- in that I agree.

I agree, as well. It reads like returning a const P.
 const / invariant alone (without brackets) is an attribute and has 
 no other meaning
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. No, seriously, I just could not possibly handle that; I would keep thinking I saw templates where there aren't any. Worse yet, for a long time I'll see the '!(' and keep wondering how I could be instantiating a template in that position, when its really a template declaration. T'is a naughty naughty thing to mix the two -- would give both the compiler and the user headaches. IMHO, its the 'const'/'invariant' keyword on methods that needs to move -- not sure where it should go, though. What looks best down here? ;) (First listing is the current state, for reference.) const P vunc (P p) { ... } P const func (P p) { ... } P const:func (P p) { ... } P const(func) (P p) { ... } P func const (P p) { ... } P func:const (P p) { ... } P func (P p) const { ... }

Definitely the last one. It's immediately familiar to anyone with a C++ background, which I guess most of those coming to D has, and which I think are the people Walter is especially targetting. It also has the added bonus of not complicating method declaration grammar too much. Same list, this time a const func returning a const return value: const const(P) func (P p) const(P) const func (P p) const(P) const(func) (P p) const(P) func const (P p) const(P) func:const (P p) const(P) func (P p) const I definitely prefer the last one as the cleanest of these.

Just chiming in on a slightly different note... the line that stuck out in both examples for me was actually the const(func) line. That seems really intuitive and consistent with the const syntax elsewhere. I do find the const-on-the-end readable too, but really mostly because of familiarity with C++ ;)

Although the idea is nice, I tried it out, and I don't like the look of it: int const(getFoo)() { return foo; } My main objection is that the const() is around getFoo, so you're saying that the function won't change -- but how can it, it's static data. What you really mean when you are saying it's a const function is that the this object is constant. So how about that? const(this) int getFoo() { return foo; } (It's syntactically unambiguous because this is a keyword) -- Reiner

Yeah, I guess there are a lot of tradeoffs with each syntax. I was wondering what the function pointers would look like as well... const int function() p; // Current const(this) int function() p; // Could be confusing in a member function int const(function)() p; // Looks like a const function pointer int function() const p; // C++ style And combinations... const(const const(int) function(const(int))) p; const(const(this) const(int) function(const(int))) p; const(const(int) const(function)(const(int))) p; const(const(int) function(const(int)) const) p; But the latter isn't really valid material for comparison. Anyways, I think the bikeshed should be orange! ;)
Aug 05 2007
parent Reiner Pope <some address.com> writes:
Paul Collier wrote:
 Reiner Pope wrote:
 Paul Collier wrote:
 Rioshin an'Harthen wrote:
 "Chris Nicholson-Sauls" <ibisbasenji gmail.com> kirjoitti viestissä 
 news:f951kq$2fss$1 digitalmars.com...
 Daniel919 wrote:
 3. const P func(P p) { ... }
 reads like: func returns a const(P)

Which is, indeed, a problem -- in that I agree.

I agree, as well. It reads like returning a const P.
 const / invariant alone (without brackets) is an attribute and has 
 no other meaning
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. No, seriously, I just could not possibly handle that; I would keep thinking I saw templates where there aren't any. Worse yet, for a long time I'll see the '!(' and keep wondering how I could be instantiating a template in that position, when its really a template declaration. T'is a naughty naughty thing to mix the two -- would give both the compiler and the user headaches. IMHO, its the 'const'/'invariant' keyword on methods that needs to move -- not sure where it should go, though. What looks best down here? ;) (First listing is the current state, for reference.) const P vunc (P p) { ... } P const func (P p) { ... } P const:func (P p) { ... } P const(func) (P p) { ... } P func const (P p) { ... } P func:const (P p) { ... } P func (P p) const { ... }

Definitely the last one. It's immediately familiar to anyone with a C++ background, which I guess most of those coming to D has, and which I think are the people Walter is especially targetting. It also has the added bonus of not complicating method declaration grammar too much. Same list, this time a const func returning a const return value: const const(P) func (P p) const(P) const func (P p) const(P) const(func) (P p) const(P) func const (P p) const(P) func:const (P p) const(P) func (P p) const I definitely prefer the last one as the cleanest of these.

Just chiming in on a slightly different note... the line that stuck out in both examples for me was actually the const(func) line. That seems really intuitive and consistent with the const syntax elsewhere. I do find the const-on-the-end readable too, but really mostly because of familiarity with C++ ;)

Although the idea is nice, I tried it out, and I don't like the look of it: int const(getFoo)() { return foo; } My main objection is that the const() is around getFoo, so you're saying that the function won't change -- but how can it, it's static data. What you really mean when you are saying it's a const function is that the this object is constant. So how about that? const(this) int getFoo() { return foo; } (It's syntactically unambiguous because this is a keyword) -- Reiner

Yeah, I guess there are a lot of tradeoffs with each syntax. I was wondering what the function pointers would look like as well... const int function() p; // Current const(this) int function() p; // Could be confusing in a member function int const(function)() p; // Looks like a const function pointer int function() const p; // C++ style And combinations... const(const const(int) function(const(int))) p; const(const(this) const(int) function(const(int))) p; const(const(int) const(function)(const(int))) p; const(const(int) function(const(int)) const) p; But the latter isn't really valid material for comparison. Anyways, I think the bikeshed should be orange! ;)

I don't know if I'm missing something, but I thought that const functions *only* exist as member functions. By which I mean that only the following makes sense: (supposing, for the purposes of this post, we adopt the existing C++ syntax) class Foo { int getX() const { return x; } } It doesn't make sense declare a free function const, and it doesn't make sense to declare a function pointer (or delegate type) const. The reason I like my syntax (at risk of being too self-centred ;) ) is that it highlights exactly what a const member function is: one with the 'this' pointer declared 'const'. I also can imagine future extensions of this syntax to express globally pure functions, with something like const(scope) or const(module). (Although they don't quite capture the essence of const(world) :-) ) -- Reiner
Aug 05 2007
prev sibling parent "Rioshin an'Harthen" <rharth75 hotmail.com> writes:
"Reiner Pope" <some address.com> kirjoitti viestissä 
news:f95nqs$lk5$1 digitalmars.com...
 Paul Collier wrote:
 Rioshin an'Harthen wrote:
 Same list, this time a const func returning a const return value:

 const const(P) func (P p)
 const(P) const func (P p)
 const(P) const(func) (P p)
 const(P) func const (P p)
 const(P) func:const (P p)
 const(P) func (P p) const

 I definitely prefer the last one as the cleanest of these.

Just chiming in on a slightly different note... the line that stuck out in both examples for me was actually the const(func) line. That seems really intuitive and consistent with the const syntax elsewhere. I do find the const-on-the-end readable too, but really mostly because of familiarity with C++ ;)

Although the idea is nice, I tried it out, and I don't like the look of it: int const(getFoo)() { return foo; } My main objection is that the const() is around getFoo, so you're saying that the function won't change -- but how can it, it's static data. What you really mean when you are saying it's a const function is that the this object is constant. So how about that? const(this) int getFoo() { return foo; } (It's syntactically unambiguous because this is a keyword)

Ok, same list as above, once again, this time using const(this) for method constness (and dropping the const(func) from the list): const(this) const(P) func (P p) const(P) const(this) func (P p) const(P) func const(this) (P p) const(P) func:const(this) (P p) const(P) func (P p) const(this) Personally, I find all of these quite unreadable this time around, although I guess I could get used to it. Too many parenthesized consts. I'll do even a list with the parameter of the function as a const: const(this) const(P) func (const(P) p) const(P) const(this) func (const(P) p) const(P) func const(this) (const(P) p) const(P) func:const(this) (const(P) p) const(P) func (const(P) p) const(this) This is getting to where my eyes start to bleed. ;) I'd still have to say that the cleanest syntax, at least to me, seems to be the last one, with the method constness indicator after the parameter list.
Aug 06 2007
prev sibling parent reply Daniel919 <Daniel919 web.de> writes:
Chris Nicholson-Sauls schrieb:
 Daniel919 wrote:
 I've got some ideas about how to make the const syntax more
 consistent.
 First I will show you the current situation.
 Then I will list the confusions and possible solutions.

 Some days ago I already mentioned my first idea on IRC, but got no 
 replies.
 Also I know that you, Walter, hardly don't change features, which
 already have been implemented.
 And my suggestions would require this of course.

 The "define proposal" is not such a big change in the language,
 in opposite to the much more important idea about
 "putting the return type in a bracket at the end".
 Because this is what the last idea requires, it's written after "WAIT:".

 Nevertheless I will give it a try, because 2.0 is still alpha and it 
 will break code compatibility anyway.



 currently the keyword const(/invariant) has three meanings:
 -----------------------------------------------------------
 1. alone: const x = 1; compile-time variable (not an lvalue)

Well technically if that was what I wanted, I'd use one of 'invariant x = 1;' or a more explicit 'final invariant(int) x = 1;'.
 2. with(): const(P) p = new Point(1,2); run-time object, which is 
 protected from changes

Well, protected from changes via this reference... but yeah. I'd say the 'const(type)' case would/should be used most often anyhow.
 3. alone: const P func(P p) { writefln(p.x, " ", p.y); }; attribute 
 for a member function: the function can't change any class fields

#3 is an issue, in my book. Not a massive one, but its there. We'll get into that one below.
 confusions and solutions:
 -------------------------
 #1
 1. const x = 1;
 2. const(P) p = new Point(1,2);
 you see const first and later recognize the brackets
 one would not expect brackets to lead to a completely different 
 meaning of the forrun keyword

My eyes are trained to spot them... still yes, a sudden shift in meaning can be counter-intuitive. Although its not entirely a shift... you could probably think of 'const x = 1;' as shorthand for 'final const(int) x = 1;'.

But they are not the same: const x = 1; doesn't take up space final const(int) x = 1; does take up space Example: struct A { const constx = 1; } struct B { final const(int) x = 1; } A.sizeof == 1 B.sizeof == 4
 1. define x = 1;
 2. const(P) p = new Point(1,2);
 can't be confused anymore, different keywords
 define defines a compile-time variable
 const / invariant has nothing to do with compile-time anymore. it only 
 means protection

Adding new keywords is usually the absolute last option around here. (There was talk ages past of replacing 'auto x = 1' with 'let x = 1'.)

You might think about spoken languages: You learn more vocabularies to be able to differentiate better, so you are more capable to express what you mean, instead of relying on an absolutely small subset of vocabularies. PS: "auto" also was a new keyword some time ago ;) "define" is also known from C/C++ world to define something you can't change, equivalent to what const x = 1; acutally means: not an lvalue. In my opinion it's better to have a different keyword for something different, and "define" makes much sense for me.
 #2
 3. const P func(P p) { ... }
 reads like: func returns a const(P)

Which is, indeed, a problem -- in that I agree.
 const / invariant alone (without brackets) is an attribute and has no 
 other meaning
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. No, seriously, I just could not possibly handle that; I would keep thinking I saw templates where there aren't any. Worse yet, for a long time I'll see the '!(' and keep wondering how I could be instantiating a template in that position, when its really a template declaration. T'is a naughty naughty thing to mix the two -- would give both the compiler and the user headaches. IMHO, its the

You are right, it really looks like a template instatiation. So lets try without the ! on declaration: func(T) (T var) (T) //IFTI take T return T func(T) (T var) //IFTI take T func(T) () (T) //IFTI return T func(T) //IFTI func(T var) (T) // take T return T func(T var) // take T func() (T) // return T func() // At least one () should remain, to make clear that it's a function Before the return brackets there must always be the take brackets. So 4. can only mean IFTI. This looks good in my opinion. To compare with the current syntax: T func(T) (T var) //IFTI take T return T void func(T) (T var) //IFTI take T T func(T) () //IFTI return T void func(T) () //IFTI T func(T var) // take T return T void func(T var) // take T T func() // return T void func() //
 'const'/'invariant' keyword on methods that needs to move -- not sure 
 where it should go, though.  What looks best down here?  ;)  (First 
 listing is the current state, for reference.)
 
 const P       vunc       (P p)       { ... }
       P const func       (P p)       { ... }
       P const:func       (P p)       { ... }
       P const(func)      (P p)       { ... }
       P       func const (P p)       { ... }
       P       func:const (P p)       { ... }
       P       func       (P p) const { ... }
 

I would suggest const: P func (P p) { ... } Not allowed: const: ... func1 ... ... func2 ... You always have to explicitly mention the "const:" for each function. This way the "attribute feeling" is retained.
 #3
 1. same meaning: invariant x = 1; const x = 1;

For basic types, there often isn't much difference anyhow. Except that invariant members of structures allocate no memory in the structure, for example.
 not allowed anymore: const(/invariant) alone is an attribute, instead 
 use:
 1. define x = 1;

 #4
 //this is ok: final int x = 1; const(int)* xptr = &x; // but:
 2. const(int) x = 1;
 this is nonsense and also atm it could be confused with:
 1. const int x = 1;

 the compiler should issue at least a warning, and instead you should use:
 1. define x = 1;


 #5
 void func(const P p) { typeof(p) == const(P) }
 bad, because one could expect this to be also valid then:
 const P p = new P(1,2); //but fails of course
 correctly is has to be:
 void func(const(P) p) { ... }
 void func(ref const(P) p) { p = new P(3,4); } //OK
 //void func(const(int) i) { ... } //const(int) nonsense (see #4)
 //void func(ref const(int) i) { ... } //const(int) nonsense (see #4)

 compiler should issue an error
 const(/invariant) alone is an attribute


 WAIT:
 -----
 because we have another syntax for compile-time variables now,
 we could say that:
 const P** ptr2ptr2P means:
 const(P**) ptr2ptr2P
 in this case, #5 would be allowed
 but this would also require #2 further proposal to be implemented, 
 because if it wasn't:
 const P** func() { ... }
 would not only be confused with, but it would be THE SAME as:
 const(P**) func() { ... }
 then the correct form would have to be:
 const func() (const P**) { ...}

 note that #4 would be true for: const int x = 1; then
 this would be nonsense, because it would be the same as: const(int) x 
 = 1;
 so the compiler should issue at least a warning



 PS: Having the return types in a bracket at the end, would make it
 possible to implement multiple return values / return tuples
 in a consistent way, too.
 It would also allow more tricks, like returning local values of a 
 function, avoiding ref, etc etc ...



 I would really enjoy to get some replies (especially yours, Walter),
 even if it's just a: "No that's totally stupid" ;)

 Best regards,
 Daniel

No that's totally stupid. Ahh I'm just kidding. At least you're thinking about the situation and offering suggestions. (And welcome to the tiny militia of 'const R func()' syntax detractors. ;)) The final/const/invariant system needs some good hammering yet -- although its off to a lovely start, danke Walter. -- Chris Nicholson-Sauls

Yes, there seem to be a lot of people not being very happy with the current const syntax. But I have not seen much concrete suggestion how to make it better. Best regards, Daniel
Aug 06 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Daniel919 wrote:
 Chris Nicholson-Sauls schrieb:
 Daniel919 wrote:
 confusions and solutions:
 -------------------------
 #1
 1. const x = 1;
 2. const(P) p = new Point(1,2);
 you see const first and later recognize the brackets
 one would not expect brackets to lead to a completely different 
 meaning of the forrun keyword

My eyes are trained to spot them... still yes, a sudden shift in meaning can be counter-intuitive. Although its not entirely a shift... you could probably think of 'const x = 1;' as shorthand for 'final const(int) x = 1;'.

But they are not the same: const x = 1; doesn't take up space final const(int) x = 1; does take up space

Just like 'invariant' does. Gotcha. Maybe the rule should be as I "suggested" with the implication that 'final' values of a basic type and an in-place initializer do not take up space? Or at least in the context of final+const|invariant. Then again, the current behavior at least works.
 Adding new keywords is usually the absolute last option around here. 
 (There was talk ages past of replacing 'auto x = 1' with 'let x = 1'.)

You might think about spoken languages: You learn more vocabularies to be able to differentiate better, so you are more capable to express what you mean, instead of relying on an absolutely small subset of vocabularies. PS: "auto" also was a new keyword some time ago ;) "define" is also known from C/C++ world to define something you can't change, equivalent to what const x = 1; acutally means: not an lvalue. In my opinion it's better to have a different keyword for something different, and "define" makes much sense for me.

Granted; I'm just saying it'll be more work to sell a new keyword. Your nomination of 'define' is itself sound. (I'm sure we'll never get the Ruby rule of "just start the name with a capital letter". ;))
 further proposal: returned types in a bracket at the end:
 3. const func (P p) (P) { ... }
 //templated syntax: const func!(T) (T p) (T) { ... }

Uhm. Ew. [etc]

You are right, it really looks like a template instatiation. So lets try without the ! on declaration: func(T) (T var) (T) //IFTI take T return T func(T) (T var) //IFTI take T func(T) () (T) //IFTI return T func(T) //IFTI func(T var) (T) // take T return T func(T var) // take T func() (T) // return T func() // At least one () should remain, to make clear that it's a function Before the return brackets there must always be the take brackets. So 4. can only mean IFTI. This looks good in my opinion.

Its... different. And I suppose workable, particularly if it were made optional -- that is, let the current syntax stand, and allow this as an alternate syntax. I do like the idea of: func() { ... } Being apparently equivelant to: void func() { ... } I think perhaps I'm just too "fond" (ie, comfortable, familiar) with the 'M... R func(A)' syntax and therefore scared to change it. Especially since it'd be a radical change at this point in the game. (At least for D/1.0)
 'const'/'invariant' keyword on methods that needs to move -- not sure 
 where it should go, though.  What looks best down here?  ;)  (First 
 listing is the current state, for reference.)

 const P       vunc       (P p)       { ... }
       P const func       (P p)       { ... }
       P const:func       (P p)       { ... }
       P const(func)      (P p)       { ... }
       P       func const (P p)       { ... }
       P       func:const (P p)       { ... }
       P       func       (P p) const { ... }

I would suggest const: P func (P p) { ... } Not allowed: const: ... func1 ... ... func2 ... You always have to explicitly mention the "const:" for each function. This way the "attribute feeling" is retained.

Actually... I like it.
 [snip]  At least you're thinking about the situation 
 and offering suggestions.  (And welcome to the tiny militia of 'const 
 R func()' syntax detractors. ;))  The final/const/invariant system 
 needs some good hammering yet -- although its off to a lovely start, 
 danke Walter.

Yes, there seem to be a lot of people not being very happy with the current const syntax. But I have not seen much concrete suggestion how to make it better.

Its a tough nut to crack. Chances are we really need to just do something crazy and new... its the coming-up-with-something-new part that's hard. A 'func(T...)(A...)(R)' function syntax, though. Now that's new. :) -- Chris Nicholson-Sauls
Aug 06 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
Chris Nicholson-Sauls Wrote:

 Yes, there seem to be a lot of people not being very happy with the 
 current const syntax.
 But I have not seen much concrete suggestion how to make it better.
 

Its a tough nut to crack. Chances are we really need to just do something crazy and new... its the coming-up-with-something-new part that's hard. A 'func(T...)(A...)(R)' function syntax, though. Now that's new. :) -- Chris Nicholson-Sauls

It's not that it's a bad idea, but there's some inner aversion to it in me. [Return type] [name] [args] has been a staple of C-based languages (and, indeed, strongly-typed languages in general). Personally, I like the const semantics except: - Compile time constants should be "invariant" only. invariant int x = 3; const int y = 3; Both x and y are compile-time constants... - Class invarinats should be better disambiguated. Personally, I like the idea of "readonly" replacing cost and "const" replacing invariant, with invariant reserved for class invarinats (thus keeping some degree of backwards compatibility).
Aug 06 2007
prev sibling next sibling parent reply Derek Parnell <derek psyc.ward> writes:
On Sun, 05 Aug 2007 14:42:09 +0200, Daniel919 wrote:


 The "define proposal" is not such a big change in the language,

I love the 'define' proposal. It is totally unambiguous and clear what is intended by the code writer, and totally unambiguous and clear about what we expect of the compiler. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Aug 06 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Derek Parnell wrote:
 On Sun, 05 Aug 2007 14:42:09 +0200, Daniel919 wrote:
 
 
 The "define proposal" is not such a big change in the language,

I love the 'define' proposal. It is totally unambiguous and clear what is intended by the code writer, and totally unambiguous and clear about what we expect of the compiler.

What I think would really rock is if 'define' could also be used for types and maybe expressions. I've long felt it was silly that aliases were backwards from normal assignments. define x = 1; define myInt = int; I'd love that. Then just get rid of alias. :-) Or maybe just allow alias to use either syntax: alias x = 1; alias 1 x; alias myInt = some_complex_expr_to_compute_a_type!(int); alias some_complex_expr_to_compute_a_type!(int) myInt; In my opinion it's a lot easier to read the assignment syntax (alias sym=thing) than the current alias syntax (alias thing sym). Mainly because, as you see above, often the 'thing' is really long, but usually the 'sym' is something very short. It makes it easier to see the thing you care about in the end which is the sym that comes out of the statement that you'll be using in subsequent code. --bb
Aug 07 2007
next sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Bill Baxter wrote:
 Derek Parnell wrote:
 On Sun, 05 Aug 2007 14:42:09 +0200, Daniel919 wrote:


 The "define proposal" is not such a big change in the language,

I love the 'define' proposal. It is totally unambiguous and clear what is intended by the code writer, and totally unambiguous and clear about what we expect of the compiler.

What I think would really rock is if 'define' could also be used for types and maybe expressions. I've long felt it was silly that aliases were backwards from normal assignments. define x = 1; define myInt = int; I'd love that. Then just get rid of alias. :-) Or maybe just allow alias to use either syntax: alias x = 1; alias 1 x; alias myInt = some_complex_expr_to_compute_a_type!(int); alias some_complex_expr_to_compute_a_type!(int) myInt; In my opinion it's a lot easier to read the assignment syntax (alias sym=thing) than the current alias syntax (alias thing sym). Mainly because, as you see above, often the 'thing' is really long, but usually the 'sym' is something very short. It makes it easier to see the thing you care about in the end which is the sym that comes out of the statement that you'll be using in subsequent code. --bb

As I understand it, the reason alias syntax is like this, is so the compiler can simply parse the alias as though it were a normal 'Type symbol;' decleration -- just like variables and functions (up until argument lists). That said, I don't imagine it would be difficult to have something of a separator in there instead, either '=' as suggested or even ':' as used to specify inheritance of classes and enums. Hmm. In fact, maybe have '=' expect an expression to define a compile-time constant, and ':' expect a type to define an alias as per current behavior. alias x = 1 ; alias myInt : some_complex_expr_to_compute_a_type!(int) ; Just thinking "aloud." -- Chris Nicholson-Sauls
Aug 07 2007
prev sibling parent Reiner Pope <some address.com> writes:
Bill Baxter wrote:
 Or maybe just allow alias to use either syntax:
 
 alias x = 1;
 alias 1 x;
 alias myInt = some_complex_expr_to_compute_a_type!(int);
 alias some_complex_expr_to_compute_a_type!(int) myInt;
 
 In my opinion it's a lot easier to read the assignment syntax (alias 
 sym=thing) than the current alias syntax (alias thing sym).  Mainly 
 because, as you see above, often the 'thing' is really long, but usually 
 the 'sym' is something very short.  It makes it easier to see the thing 
 you care about in the end which is the sym that comes out of the 
 statement that you'll be using in subsequent code.
 
 --bb

I think that would be just great. I hate having to write two templates, one for values and one for aliases. It's quite un-generic. A good example is the identity function that Andrei is keen on. It's a fair bit of work to write with templates, so that it works with types, values, and expression aliases: template Identity(T...) { static if (!is(T[0])) const Identity = T[0]; else alias T[0] Identity; } // testing static assert(is(Identity!(int) == int)); static assert(Identity!(5) == 5); int x; void main() { Identity!(x) = Identity!(5); assert(x == 5); } This currently works, but I'm not sure why[1], and it is annoying to require that. I would like to be able to write template Identity(T...) { alias T[0] Identity; } but that currently doesn't work when T[0] is a value parameter. This does actually cause problems with writing compile-time util templates, like FoldR: template FoldR(alias Fn, T...) { static if (T.length == 0) static assert(false, "Must have starting case for FoldR"); else static if (T.length == 1) { static if (is(T[0])) alias T[0] FoldR; else const FoldR = T[0]; } else { // I have to repeat this ugly recursive instantiation 3 times // because I can't keep the result -- do I alias it or use const? static if (is(FoldR!(Fn, Fn!(T[0], T[1]).val, T[2..$]))) alias FoldR!(Fn, Fn!(T[0], T[1]).val, T[2..$]) FoldR; else const FoldR = FoldR!(Fn, Fn!(T[0], T[1]).val, T[2..$]); } } So I think having alias work for values as well as types/symbols would be great. I'm not so fussed either way about alias x = int; I can see it reads better in some situations, though, and I don't see it causing any problems if both were allowed. -- Reiner [1] Here's what's confusing me (I expect it's a bug). In the first code snippet I posted, the !is(T[0]) means that types are aliased, which is good, but the call to Identity!(x) doesn't use the alias, it uses the const Identity = T[0]; part. So what is happening is effectively this: // in the instantiation of Identity!(x) const Identity = x; // in main() Identity!(x).Identity = 5; We're reassigning a constant -- how does that work? -- but somehow that causes x to change... it's oddly doing the alias itself...
Aug 07 2007
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
I realize there are some consistency issues with the current syntax for 
const, but it is more complicated than expected. Your idea to separate 
out compile time constants with a new keyword is a good one, and is 
similar to one Andrei came up with (using alias).
Aug 06 2007
next sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Walter Bright wrote:
 I realize there are some consistency issues with the current syntax for 
 const, but it is more complicated than expected. Your idea to separate 
 out compile time constants with a new keyword is a good one, and is 
 similar to one Andrei came up with (using alias).

I hadn't even considered alias. Was his idea roughly that have having "two" aliases, one of the form 'alias symbol symbol' and the other 'alias expression symbol'? Depending on how difficult it would be to implement, it might just work. If it was something else entirely, then I missed that one. -- Chris Nicholson-Sauls
Aug 07 2007
prev sibling parent Reiner Pope <some address.com> writes:
Walter Bright wrote:
 I realize there are some consistency issues with the current syntax for 
 const, but it is more complicated than expected. Your idea to separate 
 out compile time constants with a new keyword is a good one, and is 
 similar to one Andrei came up with (using alias).

If anyone is interested, there was a brief discussion on this in the D Const Design Rationale thread here: http://www.digitalmars.com/d/archives/digitalmars/D/D_const_design_rationale_54725.html#N54844 Interestingly, the use of both 'define' and 'alias' were suggested (as well as a 'literal' keyword), so it seems like those two might be quite intuitive syntaxes. -- Reiner
Aug 07 2007