www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Latest const expansion

reply Regan Heath <regan netmail.co.nz> writes:
I'm interested in what people think of the idea(s) I had for expanding 
on Walter's latest const proposal and handling head/tail const on class 
references.

Ideas originally posted as replies, here:

http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=58107
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=58112

Also here:

http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=58114
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=58115


In short, Where:

head const - means the class reference itself cannot be modified
tail const - means the class members cannot be modified

Where T is a class:

const(T)  indicates both head/tail const
const(*T) indicates tail const
const(&T) indicates head const

Eg.

class A { int a; }

const(A)  a;  //a cannot be modified, a.a cannot be modified
const(*A) b;  //a can be modified, a.a cannot be modified
const(&A) c;  //a cannot be modified, a.a can be modified

The idea being that const(*T) means const("value of the type T") where 
the value of a class reference is the class instance itself.  Likewise 
const(&T) means const("reference/pointer of the type T") indicating the 
reference is to be const.

For template/meta-programming purposes the syntax "const(*T)" and 
"const(&T)" should be legal for T where T is a value type, i.e. struct, 
union, and primitives (excluding pointers) but will be identical in 
behaviour to "const(T)"


For pointers and arrays the "const(*T)" (tail const) syntax is not 
required as we can say:

const(T)[]
const(T)*

but perhaps for meta-programming purposes it should be legal, eg.

const(*char[])
const(*char*)


For pointers and arrays the "const(&T)" (head const) syntax is required 
as there is currently no way to get a const array reference to mutable 
data, so:

const(&char[])
const(&char*)

would specify a const array reference and const pointer respecitvely 
both to mutable 'char' data.

Thoughts?  Too complicated?  :P

Regan
Sep 11 2007
next sibling parent reply Alexander Panek <alexander.panek brainsware.org> writes:
Regan Heath wrote:
 Thoughts?  Too complicated?  :P
It's a tad complicated, but makes sense. More sense - to me - than the former const/invariant/final and the upcoming const/invariant combinations. At least you summed it up in a way so I understand it. :) Yet, I have some questions: -- class A { int i; } const(*A) a; -- Do I understand correctly? The variable `a' - as in a reference to an instance of `class A' is mutable, but the instance `a' refers to is not? (read as: `class A { const { int i; ... } }', just for this instance reference) This also means, that you can reference to another instance with `a': -- a = b; -- Right? -- const(&A) a; -- This means, that the reference to the class instance is not mutable, yet the actual instance is? What exactly do `const(T)[]' and `const(T)*' imply? Immutable data, or immutable reference/pointer? .. I think that's it for now. So long, and thanks for the fish. Best regards, Alex
Sep 11 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Alexander Panek wrote:
 Regan Heath wrote:
 Thoughts?  Too complicated?  :P
It's a tad complicated, but makes sense. More sense - to me - than the former const/invariant/final and the upcoming const/invariant combinations. At least you summed it up in a way so I understand it. :) Yet, I have some questions: -- class A { int i; } const(*A) a; -- Do I understand correctly? The variable `a' - as in a reference to an instance of `class A' is mutable, but the instance `a' refers to is not? (read as: `class A { const { int i; ... } }', just for this instance reference) This also means, that you can reference to another instance with `a': -- a = b; -- Right?
Correct.
 -- 
 const(&A) a;
 -- 
 This means, that the reference to the class instance is not mutable, yet 
 the actual instance is?
Correct.
 What exactly do `const(T)[]' and `const(T)*' imply? Immutable data, or 
 immutable reference/pointer?
Immutable data. Regan
Sep 11 2007
next sibling parent Alexander Panek <alexander.panek brainsware.org> writes:
Regan Heath wrote:
 Correct.
 Correct.
 Immutable data.
I liek. /me votes up.
Sep 11 2007
prev sibling parent Regan Heath <regan netmail.co.nz> writes:
Regan Heath wrote:
 Alexander Panek wrote:
 Regan Heath wrote:
 Thoughts?  Too complicated?  :P
It's a tad complicated, but makes sense. More sense - to me - than the former const/invariant/final and the upcoming const/invariant combinations. At least you summed it up in a way so I understand it. :) Yet, I have some questions: -- class A { int i; } const(*A) a; -- Do I understand correctly? The variable `a' - as in a reference to an instance of `class A' is mutable, but the instance `a' refers to is not? (read as: `class A { const { int i; ... } }', just for this instance reference) This also means, that you can reference to another instance with `a': -- a = b; -- Right?
Correct.
 -- 
 const(&A) a;
 -- 
 This means, that the reference to the class instance is not mutable, 
 yet the actual instance is?
Correct.
 What exactly do `const(T)[]' and `const(T)*' imply? Immutable data, or 
 immutable reference/pointer?
Immutable data.
Slight correction; 'data' in this case is whatever the type of T is, which could be a class reference or a pointer, of course. Regan
Sep 11 2007
prev sibling next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Regan Heath wrote:
 I'm interested in what people think of the idea(s) I had for expanding 
 on Walter's latest const proposal and handling head/tail const on class 
 references.
 
 Ideas originally posted as replies, here:
 
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmar
.D&article_id=58107 
 
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmar
.D&article_id=58112 
 
 
 Also here:
 
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmar
.D&article_id=58114 
 
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmar
.D&article_id=58115 
 
 
 
 In short, Where:
 
 head const - means the class reference itself cannot be modified
 tail const - means the class members cannot be modified
 
 Where T is a class:
 
 const(T)  indicates both head/tail const
 const(*T) indicates tail const
 const(&T) indicates head const
 
 Eg.
 
 class A { int a; }
 
 const(A)  a;  //a cannot be modified, a.a cannot be modified
 const(*A) b;  //a can be modified, a.a cannot be modified
 const(&A) c;  //a cannot be modified, a.a can be modified
 
 The idea being that const(*T) means const("value of the type T") where 
 the value of a class reference is the class instance itself.  Likewise 
 const(&T) means const("reference/pointer of the type T") indicating the 
 reference is to be const.
 
 For template/meta-programming purposes the syntax "const(*T)" and 
 "const(&T)" should be legal for T where T is a value type, i.e. struct, 
 union, and primitives (excluding pointers) but will be identical in 
 behaviour to "const(T)"
 
 
 For pointers and arrays the "const(*T)" (tail const) syntax is not 
 required as we can say:
 
 const(T)[]
 const(T)*
 
 but perhaps for meta-programming purposes it should be legal, eg.
 
 const(*char[])
 const(*char*)
 
 
 For pointers and arrays the "const(&T)" (head const) syntax is required 
 as there is currently no way to get a const array reference to mutable 
 data, so:
 
 const(&char[])
 const(&char*)
 
 would specify a const array reference and const pointer respecitvely 
 both to mutable 'char' data.
 
 Thoughts?  Too complicated?  :P
 
 Regan
Hello, I'm a new user of D. I've read about the const system and i agree with everyone who wants a head/tail const. however i disagree with the sytax proposed by various people as being unreadable. const(*char*) or const (&char**) is quite confusing in my opinion. my proposal is to simply use the terms tail/head, so the syntax will be [head|tail] const (T) | const T for example: head const (C) c; // c is const but c.x isn't tail const (C) c; // c is mutable but c.x is const const (C) c; // as before, both c and c.x are const head const C c; // Error tail const C c; // Error Yigal Chripun
Sep 11 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 9/11/07, Yigal Chripun <yigal100 gmail.com> wrote:
 my proposal is to simply use the terms tail/head, so the syntax will be
 [head|tail] const (T) | const T

 for example:
 head const (C) c; // c is const but c.x isn't
 tail const (C) c; // c is mutable but c.x is const
 const (C) c; // as before, both c and c.x are const
 head const C c; // Error
 tail const C c; // Error
head and tail are good variable names, so I'd rather they didn't become reserved words. But I've no problem with headconst and tailconst. Only ... would that mean we'd then also have to have a tailtailconst?
Sep 11 2007
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Janice Caron wrote:
 On 9/11/07, Yigal Chripun <yigal100 gmail.com> wrote:
 my proposal is to simply use the terms tail/head, so the syntax will be
 [head|tail] const (T) | const T

 for example:
 head const (C) c; // c is const but c.x isn't
 tail const (C) c; // c is mutable but c.x is const
 const (C) c; // as before, both c and c.x are const
 head const C c; // Error
 tail const C c; // Error
head and tail are good variable names, so I'd rather they didn't become reserved words. But I've no problem with headconst and tailconst. Only ... would that mean we'd then also have to have a tailtailconst?
agreed, no need to make tail/head reserved words. i thought 1 level of "tailness" is enough to cover 99% of cases... can you give a use case for "tailtailconst" that can't be resolved with a combination of the const parens and tailconst?
Sep 11 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Yigal Chripun wrote:
 Janice Caron wrote:
 On 9/11/07, Yigal Chripun <yigal100 gmail.com> wrote:
 my proposal is to simply use the terms tail/head, so the syntax will be
 [head|tail] const (T) | const T

 for example:
 head const (C) c; // c is const but c.x isn't
 tail const (C) c; // c is mutable but c.x is const
 const (C) c; // as before, both c and c.x are const
 head const C c; // Error
 tail const C c; // Error
head and tail are good variable names, so I'd rather they didn't become reserved words. But I've no problem with headconst and tailconst. Only ... would that mean we'd then also have to have a tailtailconst?
agreed, no need to make tail/head reserved words. i thought 1 level of "tailness" is enough to cover 99% of cases... can you give a use case for "tailtailconst" that can't be resolved with a combination of the const parens and tailconst?
I think tailconst is too long a word for something that will probably be used pretty frequently. If you think of C++ the most commonly used const with pointer types is "const T* foo;" which means tail const. The equivalent with a D class would be come "tailconst T foo" and you'd have cases where "tailconst" appears 5 times in a function signature. tailconst Z some_func(tailconst A a, tailconst B b, tailconst C c, tailconst D d) { ... } Ick. How about shortening it to just "tconst"? And there could be ttconst, and tttconst as needed. Similarly "hconst". And still the const(T)* syntax can be a synonym for tconst(T*). Kinda reminiscent of cons, cdr, cddr, cdddr, from lisp, which really are basically serving the same purpose. --bb
Sep 11 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
news:fc72rn$rjv$1 digitalmars.com...
 Kinda reminiscent of cons, cdr, cddr, cdddr, from lisp, which really are 
 basically serving the same purpose.
I was SO going to make that reference. Man my day is just RUINED.
Sep 11 2007
parent reply Mike Streatfield <dnewsgroup.c talyst.me.uk> writes:
Jarrett Billingsley wrote:
 "Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
 news:fc72rn$rjv$1 digitalmars.com...
 Kinda reminiscent of cons, cdr, cddr, cdddr, from lisp, which really are 
 basically serving the same purpose.
I was SO going to make that reference. Man my day is just RUINED.
I was SO going to make that retort to that reference. Man my day is just META-RUINED.
Sep 12 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Mike Streatfield" <dnewsgroup.c talyst.me.uk> wrote in message 
news:fc97mq$1jov$1 digitalmars.com...
 I was SO going to make that retort to that reference. Man my day is just 
 META-RUINED.
My brain literally just exploded.
Sep 12 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Regan Heath wrote:
 const(T)  indicates both head/tail const
 const(*T) indicates tail const
 const(&T) indicates head const
I think this befuddles the nice clean idea of const(...) as a type constructor that takes the type inside the parens and makes a new const-ified type out of it. But fortunately that cleanness can be reclaimed by thinking instead of a _family_ of type constructors, which do head/tail/full const of their argument. In short, just move the symbol out of the parens so the thing inside the parens remains a valid type. const(T) - type constructor making both head/tail const version of T const*(T) - type constructor making tail const version of T const**(T) - type constructor making tail-of-tail const version of T [..and now we're back to what I think was Janice's suggestion many many posts ago, which I liked then too.] I think this is quite logical. The const*() type constructor can be thought of as dereferencing the type in parens by one level and *then* applying the constness to the result, and then returning a reference to that type. For example const*(int*): dereference int* to get --> int apply const to get --> const(int) address-of to get --> const(int)* So in this case it's the same as const(int)*. But for a class, const*(C), it lets you do something that can't be done by peeling off the pointer. That's tail const. I'm not so sure I like using const&(T) to mean head const, though. It doesn't really seem right for some reason. Using the * for tail has an interpretation in terms of performing an actual dereference on an object, then applying full const. But const&() doesn't really have such an interpretation. You're not taking the address and then applying full const. So for that reason another keyword is preferable I think. Like 'final'. Or maybe headconst or 'hconst'. --bb
Sep 11 2007
next sibling parent 0ffh <spam frankhirsch.net> writes:
Bill Baxter wrote:
 const(T) - type constructor making both head/tail const version of T
 const*(T) - type constructor making tail const version of T
 const**(T) - type constructor making tail-of-tail const version of T
++vote;
 I'm not so sure I like using const&(T) to mean head const, though.  It 
 doesn't really seem right for some reason.
A couple of suggestions for T const, *T mutable: 1) *const(T) - "reverse" of the suggested tail const syntax 2) mutable*(const(T)) - a bit keyboard intensive, but nicely obvious Regards, Frank
Sep 11 2007
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 9/11/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 So for that reason another
 keyword is preferable I think.  Like 'final'.  Or maybe headconst or
 'hconst'.
We've had the keyword final for some time in D2.0, specifically for the purpose of head-constness, so if it's deemed that we need it, final would be as good a keyword as any. But do we need it? Is there a need for head const at all? Walter seems to have concluded that it's not needed. And every use case I can think of could be done by other means, so I think I agree. In every single circumstance I can think of, headconst(T) x; could simply be replaced by T x; and nothing would fall over. What is gained by the head-constness? It's totally local.
Sep 11 2007
parent Regan Heath <regan netmail.co.nz> writes:
Janice Caron wrote:
 On 9/11/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 So for that reason another
 keyword is preferable I think.  Like 'final'.  Or maybe headconst or
 'hconst'.
We've had the keyword final for some time in D2.0, specifically for the purpose of head-constness, so if it's deemed that we need it, final would be as good a keyword as any. But do we need it? Is there a need for head const at all? Walter seems to have concluded that it's not needed. And every use case I can think of could be done by other means, so I think I agree. In every single circumstance I can think of, headconst(T) x; could simply be replaced by T x; and nothing would fall over. What is gained by the head-constness? It's totally local.
Local to the body of a class, for example. Local to the global scope of the program also. I think it's useful in that it provides a guarantee that a reference/pointer itself will never change, which is a boon for multithreaded work for example. Allowing reads using that reference/pointer without locking (in some cases). Regan
Sep 12 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 Regan Heath wrote:
 const(T)  indicates both head/tail const
 const(*T) indicates tail const
 const(&T) indicates head const
That's pretty much a horrendous syntax, and I hope I'm not the only to think that.
 I think this befuddles the nice clean idea of const(...) as a type 
 constructor that takes the type inside the parens and makes a new 
 const-ified type out of it.
 
 But fortunately that cleanness can be reclaimed by thinking instead of a 
 _family_ of type constructors, which do head/tail/full const of their 
 argument.  In short, just move the symbol out of the parens so the thing 
 inside the parens remains a valid type.
 
 const(T) - type constructor making both head/tail const version of T
 const*(T) - type constructor making tail const version of T
 const**(T) - type constructor making tail-of-tail const version of T
 
 [..and now we're back to what I think was Janice's suggestion many many 
 posts ago, which I liked then too.]
 
Yes, I like this better too. The '*'s are not mixed the 'T', which is better. But like I mentioned in Janice's thread, I think it would be even better to have this: final const(T) - head/tail const const(T) - tail const ... and tail-of-tail const would not be supported, at least not with a native syntax. I don't see much use for it, so let's keep it simple (but should there be a use, such a construct could be made with meta-programming anyway). -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 12 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 9/13/07, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:
 I think it would be
 even better to have this:

 final const(T) - head/tail const
 const(T)       - tail const
That's what we had in D2.0. That's what we've just got rid of. Almost nobody likes the notion that const(T) should mean something different from const T. That idea has already been rejected as being too confusing.
Sep 12 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On 9/13/07, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:
 I think it would be
 even better to have this:

 final const(T) - head/tail const
 const(T)       - tail const
That's what we had in D2.0. That's what we've just got rid of. Almost nobody likes the notion that const(T) should mean something different from const T. That idea has already been rejected as being too confusing.
I think const(T) was going to mean the same thing as const T for simple value types, no? The thing that's confusing is that that it also means the same thing as just plain T for a simple value type. That and the fact that this const(T)* foo; // T's can't change pointer can. is not the same as: alias const(T) S; // S is same as a T, actually S* foo; // no const here anymore. .. or maybe it was the same... I can't remember what was what now. --bb
Sep 13 2007
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Janice Caron wrote:
 On 9/13/07, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:
 I think it would be
 even better to have this:

 final const(T) - head/tail const
 const(T)       - tail const
That's what we had in D2.0. That's what we've just got rid of.
No, it's not what he have now in D2.0. I said that const(T) should mean "tail const". Since I didn't mention anything else, it should be inferred that I mean that const(T) should mean "tail const" *everywhere*. In D2.0 const(T) means "tail const" if it's at the top level of a declaration, and if it is not it means "head/tail const". That behavior is of course, different from my suggestion. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 13 2007
prev sibling parent reply Bruce Adams <tortoise_74 ya.thewho.co.uk> writes:
Bill Baxter Wrote:

 Yigal Chripun wrote:
 Janice Caron wrote:
 On 9/11/07, Yigal Chripun <yigal100 gmail.com> wrote:
 my proposal is to simply use the terms tail/head, so the syntax will be
 [head|tail] const (T) | const T

 for example:
 head const (C) c; // c is const but c.x isn't
 tail const (C) c; // c is mutable but c.x is const
 const (C) c; // as before, both c and c.x are const
 head const C c; // Error
 tail const C c; // Error
head and tail are good variable names, so I'd rather they didn't become reserved words. But I've no problem with headconst and tailconst. Only ... would that mean we'd then also have to have a tailtailconst?
agreed, no need to make tail/head reserved words. i thought 1 level of "tailness" is enough to cover 99% of cases... can you give a use case for "tailtailconst" that can't be resolved with a combination of the const parens and tailconst?
I think tailconst is too long a word for something that will probably be used pretty frequently. If you think of C++ the most commonly used const with pointer types is "const T* foo;" which means tail const. The equivalent with a D class would be come "tailconst T foo" and you'd have cases where "tailconst" appears 5 times in a function signature. tailconst Z some_func(tailconst A a, tailconst B b, tailconst C c, tailconst D d) { ... } Ick. How about shortening it to just "tconst"? And there could be ttconst, and tttconst as needed. Similarly "hconst". And still the const(T)* syntax can be a synonym for tconst(T*). Kinda reminiscent of cons, cdr, cddr, cdddr, from lisp, which really are basically serving the same purpose. --bb
You sick puppy. If I hadn't seen your many other wonderful posts I'd assume you were trolling with that one. Keyword profilerifation is a classic language design anti-pattern. If you must go down that route then your "const" should be parameterisable. I'm not terribly keen on that idea either.
Sep 12 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Bruce Adams wrote:
 Bill Baxter Wrote:
 
 Yigal Chripun wrote:
 Janice Caron wrote:
 On 9/11/07, Yigal Chripun <yigal100 gmail.com> wrote:
 my proposal is to simply use the terms tail/head, so the syntax will be
 [head|tail] const (T) | const T

 for example:
 head const (C) c; // c is const but c.x isn't
 tail const (C) c; // c is mutable but c.x is const
 const (C) c; // as before, both c and c.x are const
 head const C c; // Error
 tail const C c; // Error
head and tail are good variable names, so I'd rather they didn't become reserved words. But I've no problem with headconst and tailconst. Only ... would that mean we'd then also have to have a tailtailconst?
agreed, no need to make tail/head reserved words. i thought 1 level of "tailness" is enough to cover 99% of cases... can you give a use case for "tailtailconst" that can't be resolved with a combination of the const parens and tailconst?
I think tailconst is too long a word for something that will probably be used pretty frequently. If you think of C++ the most commonly used const with pointer types is "const T* foo;" which means tail const. The equivalent with a D class would be come "tailconst T foo" and you'd have cases where "tailconst" appears 5 times in a function signature. tailconst Z some_func(tailconst A a, tailconst B b, tailconst C c, tailconst D d) { ... } Ick. How about shortening it to just "tconst"? And there could be ttconst, and tttconst as needed. Similarly "hconst". And still the const(T)* syntax can be a synonym for tconst(T*). Kinda reminiscent of cons, cdr, cddr, cdddr, from lisp, which really are basically serving the same purpose. --bb
You sick puppy. If I hadn't seen your many other wonderful posts I'd assume you were trolling with that one. Keyword profilerifation is a classic language design anti-pattern. If you must go down that route then your "const" should be parameterisable. I'm not terribly keen on that idea either.
Heh. Well I'd prefer the const*(T), const**(T) thing I posted previously. But if people don't go for that I'd rather at least have short keywords rather than a beasts like "tailconst" and "tailtailconst". :-) --bb
Sep 12 2007