www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - The problem with const proposals

reply Gregor Richards <Richards codu.org> writes:
Not a single person on this board (and I mean NO ONE) has a grasp over 
everything that one can reasonably expect const to do. What we need to 
do is construct a complete list of features that the const system ought 
to have, so that any const proposal can be checked against the "good 
clean const fun" checklist. Instead, what we have is suggestion after 
suggestion, each with good points but each with fundamental flaws. We're 
never going to get anywhere like this because nobody knows what everyone 
needs.

Disclaimer: It is of course impossible to make a list that makes 
everyone happy. C'est la vie.

  - Gregor Richards
Dec 07 2007
next sibling parent Alexander Panek <alexander.panek brainsware.org> writes:
On Fri, 07 Dec 2007 08:31:43 -0800
Gregor Richards <Richards codu.org> wrote:

 Not a single person on this board (and I mean NO ONE) has a grasp
 over everything that one can reasonably expect const to do. What we
 need to do is construct a complete list of features that the const
 system ought to have, so that any const proposal can be checked
 against the "good clean const fun" checklist. Instead, what we have
 is suggestion after suggestion, each with good points but each with
 fundamental flaws. We're never going to get anywhere like this
 because nobody knows what everyone needs.
 
 Disclaimer: It is of course impossible to make a list that makes 
 everyone happy. C'est la vie.
 
   - Gregor Richards
me too. -- Alexander Panek <alexander.panek brainsware.org>
Dec 07 2007
prev sibling next sibling parent mandel <oh no.es> writes:
On Fri, 07 Dec 2007 08:31:43 -0800, Gregor Richards wrote:

 Not a single person on this board (and I mean NO ONE) has a grasp over
 everything that one can reasonably expect const to do. What we need to
 do is construct a complete list of features that the const system ought
 to have, so that any const proposal can be checked against the "good
 clean const fun" checklist.
Can't someone make a checklist on some wiki? All those different ideas are confusing and time consuming.
Dec 07 2007
prev sibling next sibling parent reply "Craig Black" <cblack ara.com> writes:
"Gregor Richards" <Richards codu.org> wrote in message 
news:fjbshj$2273$1 digitalmars.com...
 Not a single person on this board (and I mean NO ONE) has a grasp over 
 everything that one can reasonably expect const to do. What we need to do 
 is construct a complete list of features that the const system ought to 
 have, so that any const proposal can be checked against the "good clean 
 const fun" checklist. Instead, what we have is suggestion after 
 suggestion, each with good points but each with fundamental flaws. We're 
 never going to get anywhere like this because nobody knows what everyone 
 needs.

 Disclaimer: It is of course impossible to make a list that makes everyone 
 happy. C'est la vie.

  - Gregor Richards
I don't really see what your point is. We should drop const altogether? I agree with your observation in part. However, it is beneficial to discuss and hash out ideas. Discussion helps everyone understand const better. Yes, no single person can grasp all the complexities of const, but perhaps together we can arrive at a better solution.
Dec 07 2007
parent reply Gregor Richards <Richards codu.org> writes:
Craig Black wrote:
 "Gregor Richards" <Richards codu.org> wrote in message 
 news:fjbshj$2273$1 digitalmars.com...
 Not a single person on this board (and I mean NO ONE) has a grasp over 
 everything that one can reasonably expect const to do. What we need to do 
 is construct a complete list of features that the const system ought to 
 have, so that any const proposal can be checked against the "good clean 
 const fun" checklist. Instead, what we have is suggestion after 
 suggestion, each with good points but each with fundamental flaws. We're 
 never going to get anywhere like this because nobody knows what everyone 
 needs.

 Disclaimer: It is of course impossible to make a list that makes everyone 
 happy. C'est la vie.

  - Gregor Richards
I don't really see what your point is. We should drop const altogether? I agree with your observation in part. However, it is beneficial to discuss and hash out ideas. Discussion helps everyone understand const better. Yes, no single person can grasp all the complexities of const, but perhaps together we can arrive at a better solution.
... are we speaking the same language? My point is that we should, as a group, create (or "hash out") a list of concepts that const must encompass, rather than creating syntax proposal after syntax proposal, so that we'll actually have something to test the syntax proposals against. - Gregor Richards
Dec 07 2007
parent "Craig Black" <cblack ara.com> writes:
 ... are we speaking the same language?

 My point is that we should, as a group, create (or "hash out") a list of 
 concepts that const must encompass, rather than creating syntax proposal 
 after syntax proposal, so that we'll actually have something to test the 
 syntax proposals against.

  - Gregor Richards
Sorry I misunderstood you. Yes good idea.
Dec 07 2007
prev sibling next sibling parent =?ISO-8859-1?Q?S=F6nke_Ludwig?= writes:
Gregor Richards wrote:
 Not a single person on this board (and I mean NO ONE) has a grasp over 
 everything that one can reasonably expect const to do. What we need to 
 do is construct a complete list of features that the const system ought 
 to have, so that any const proposal can be checked against the "good 
 clean const fun" checklist. Instead, what we have is suggestion after 
 suggestion, each with good points but each with fundamental flaws. We're 
 never going to get anywhere like this because nobody knows what everyone 
 needs.
 
 Disclaimer: It is of course impossible to make a list that makes 
 everyone happy. C'est la vie.
 
  - Gregor Richards
I think - functionally - most of the proposals so far would suffice. But it would sure be interesting to have a more or less representative coverage measure. From my personal experience with working on a fairly complex codebase (about 500 modules/classes), which was first partially ported from C++ to non-const-D, before 2.0 was out and since then has got const/invariant brought in, my list would roughly be: arrays: const(T)[] const(T[]) tailconst(C)[] const(C[]) T[const(C)] const(T)*[] pointers: const(T)* const(T*) inside structs/classes: tailconst(C) invariant T (C=class, T=any) The same goes for invariant. This is from a quick grep over the code base including some workarounds for things which are currently impossible in that form. The more complex type constructs I've found are only used locally without const or are implicit like in "auto pointerToClassRef = key in assocarray;". Other related things are some invariant classes and const/invariant member functions. Also, in the beginning I occasionally missed non-transitive const, but that has not been a problem since then.
Dec 07 2007
prev sibling next sibling parent reply guslay <guslay gmail.com> writes:
Here is my list so far (examples are just for illustration, I do not propose a
syntax):


1- non-addressable constant value (we can distinguish two conceptual flavors)
    a - constant primive (aka define)
    b - enumeration

2- immutable value type (addressable)
      - current const/invariant (they represent the same thing, don't they?)
        ex. const int x = 42; const S s(0,0);

3- immutable reference type (aka pointer to const data)
    a - reference immutable class
        ex. const C c = new C(0,0);

    b - pointer to immutable value
        ex. const (T)* s; //ptr to const T
        ex. const (T*) s; //const ptr to const T

4- aggregates (arrays etc)
    a - mutable container of const data
        ex. const(T)[]

    b - immutable container of const data
        ex. const(T[])

    c - immutable container of mutable data
        ex. ?? T[const]

5- non-rebindable value
      - pointless, basically covered by 1

6- non-rebindable reference (aka const pointer to data)
    a - to mutable data
        ex. final S* s; final C;

    b - to immutable data
        ex. final const S* s; final const C;


There might be some overlap (eg. between 3b and 6).
Dec 07 2007
next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 12/7/07, guslay <guslay gmail.com> wrote:
 Here is my list so far
But what is it a list /of/? I ask because item 6a violates const-transitivity, and const-transitivity is itself deemed to be a requirement of the D programming language. Are we compiling a list of conflicting requirement here? My list would be much shorter. It would be that const should be: (1) simple to understand (2) transitive (3) compatible with generic programming ...and that's kind of it, really.
Dec 07 2007
next sibling parent reply Paul Anderson <paul.d.anderson.removethis comcast.andthis.net> writes:
Janice Caron Wrote:

 On 12/7/07, guslay <guslay gmail.com> wrote:
 Here is my list so far
But what is it a list /of/? I ask because item 6a violates const-transitivity, and const-transitivity is itself deemed to be a requirement of the D programming language. Are we compiling a list of conflicting requirement here? My list would be much shorter. It would be that const should be: (1) simple to understand (2) transitive (3) compatible with generic programming ...and that's kind of it, really.
<why can't we all just get along?> I think that guslay's list distills a lot of the discussion here, at least about what people want. I agree that it is a good idea to have such a list to guide our discussion. I agree with Janice that such a list needs to be defined and scrubbed for consistency. Maybe we could have a compiler switch that turns const features and const keywords on and off? </why can't we all just get along?> Paul
Dec 07 2007
parent Christopher Wright <dhasenan gmail.com> writes:
Paul Anderson wrote:
 Maybe we could have a compiler switch that turns const features and const
keywords on and off?
I want to compile my app with your const-a-f-o library and someone else's const-b-t-r library. I'm screwed. Until DMD can create good precompiled libraries, that is.
Dec 07 2007
prev sibling parent reply =?ISO-8859-1?Q?S=F6nke_Ludwig?= writes:
Janice Caron wrote:
 On 12/7/07, guslay <guslay gmail.com> wrote:
 Here is my list so far
But what is it a list /of/? I ask because item 6a violates const-transitivity, and const-transitivity is itself deemed to be a requirement of the D programming language. Are we compiling a list of conflicting requirement here? My list would be much shorter. It would be that const should be: (1) simple to understand (2) transitive (3) compatible with generic programming ...and that's kind of it, really.
I'd add (4) nice, intuitive syntax (as far as that's possible)
Dec 07 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sönke Ludwig wrote:
 I'd add (4) nice, intuitive syntax (as far as that's possible)
Unfortunately, that's not a design requirement that can be tested.
Dec 07 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Sönke Ludwig wrote:
 I'd add (4) nice, intuitive syntax (as far as that's possible)
Unfortunately, that's not a design requirement that can be tested.
Dec 07 2007
prev sibling parent Graham St Jack <Graham.StJack internode.on.net> writes:
On Fri, 07 Dec 2007 12:59:52 -0500, guslay wrote:

 Here is my list so far (examples are just for illustration, I do not
 propose a syntax):
 
 
 1- non-addressable constant value (we can distinguish two conceptual
 flavors)
     a - constant primive (aka define)
     b - enumeration
 
 2- immutable value type (addressable)
       - current const/invariant (they represent the same thing, don't
       they?)
         ex. const int x = 42; const S s(0,0);
 
 3- immutable reference type (aka pointer to const data)
     a - reference immutable class
         ex. const C c = new C(0,0);
 
     b - pointer to immutable value
         ex. const (T)* s; //ptr to const T
         ex. const (T*) s; //const ptr to const T
 
 4- aggregates (arrays etc)
     a - mutable container of const data
         ex. const(T)[]
 
     b - immutable container of const data
         ex. const(T[])
 
     c - immutable container of mutable data
         ex. ?? T[const]
 
 5- non-rebindable value
       - pointless, basically covered by 1
 
 6- non-rebindable reference (aka const pointer to data)
     a - to mutable data
         ex. final S* s; final C;
 
     b - to immutable data
         ex. final const S* s; final const C;
 
 
 There might be some overlap (eg. between 3b and 6).
Don't forget const and invariant methods and all that goes with them.
Dec 11 2007
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Gregor Richards wrote:
 Not a single person on this board (and I mean NO ONE) has a grasp over 
 everything that one can reasonably expect const to do. What we need to 
 do is construct a complete list of features that the const system ought 
 to have, so that any const proposal can be checked against the "good 
 clean const fun" checklist. Instead, what we have is suggestion after 
 suggestion, each with good points but each with fundamental flaws. We're 
 never going to get anywhere like this because nobody knows what everyone 
 needs.
It's not fair injecting sense into this <g>. I've certainly spent the last year discovering what doesn't work because of this or that. It does pay to now and then go back and remember exactly what problem one is trying to solve in the first place.
Dec 07 2007
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
In developing D, I've found it very helpful to think in terms of 
"axioms", which are fundamental principles that one can test a design 
against. If any tests fail, then one must change the design, or perhaps 
one discovers that the axioms aren't really axioms at all. It's 
analogous to mathematical axioms. In fact, Andrei pointed out that if we 
adhere to axioms, then we can do mathematical proofs about D, such as 
proof of correctness.

For example, in physics we have the axioms:

1) entropy always increases
2) mass and energy are conserved

so if we have a fellow with a new perpetual motion machine design, we 
automatically know he's a crackpot.

In economics, we have the axiom:

1) There ain't no such thing as a free lunch.

and any economic theory that produces something for nothing is a 
crackpot theory.

So, what are our axioms for const/invariant?

1) Const/invariant are transitive.
2) Any type T can be wrapped inside a struct S, and that S can be made 
to behave as a typedef for type T.
3) The contents of invariant types, once constructed, can never change.
4) The contents of const types, once constructed, can never be changed 
through those const contents.
5) For any type T, we can construct a const(T) or an invariant(T) 
without knowing anything about T.
Dec 07 2007
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:
 So, what are our axioms for const/invariant?
 
 1) Const/invariant are transitive.
 2) Any type T can be wrapped inside a struct S, and that S can be made 
 to behave as a typedef for type T.
 3) The contents of invariant types, once constructed, can never change.
 4) The contents of const types, once constructed, can never be changed 
 through those const contents.
 5) For any type T, we can construct a const(T) or an invariant(T) 
 without knowing anything about T.
I'd like to see a list of goals that drive axiom development. The list below includes some of the stuff posted by others plus additional stuff. (a) simple to understand (b) nice, intuitive syntax (c) compatible with generic programming (d) compatible with functional programming (e) compatible with compiler optimization (f) const guarantees for API's I'm not sure where axiom 2 comes from. I believe the requirement for invariant comes in from (d) and (e) while the requirement for const comes from (f). I'd love to see "const X" == "const(X)" as an axiom ;) In the past, when considering const, I found it very helpful to think about when implicit casts to (scoped) const/invariant are valid. I believe that in the current design, there's no way for the compiler to guarantee that a cast to invariant is valid because there's never a guarantee that a non-invariant bit of data will be written to by something else. IMHO, having well defined cases when casting is safe should be another requirement.
Dec 07 2007
next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/7/07, Jason House <jason.james.house gmail.com> wrote:
 I'm not sure where axiom 2 comes from.
But it's certainly a desirable one. I'd prioritise axiom 2 any day. Not happy with type T? Well, wrap it in a struct, add a few functions, and viola - a new type that's just like a T, only better in whatever ways you care to code. It's a good axiom. ...and it impacts tail-constness, which is why Walter listed it in this thread. In order to comply with the axiom, it must be possible to make tailconst( struct { T }) behave like struct { tailconst(T) } and that's something which has not been addressed by any syntax proposal so far, /except/ for Andrei's TailConst!() template. ...which is one reason why I like the template idea.
Dec 07 2007
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 I'd love to see "const X" == "const(X)" as an axiom ;)
I've tried to avoid having a specific syntax as an axiom, because ideally the syntax should be derivable from the axioms.
 I
 believe that in the current design, there's no way for the compiler
 to guarantee that a cast to invariant is valid because there's never
 a guarantee that a non-invariant bit of data will be written to by
 something else.
There have been some papers written about this. Unfortunately, the various designs for it just aren't workable.
Dec 07 2007
prev sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Walter Bright wrote:

 So, what are our axioms for const/invariant?
 
 1) Const/invariant are transitive.
 2) Any type T can be wrapped inside a struct S, and that S can be made 
 to behave as a typedef for type T.
 3) The contents of invariant types, once constructed, can never change.
 4) The contents of const types, once constructed, can never be changed 
 through those const contents.
 5) For any type T, we can construct a const(T) or an invariant(T) 
 without knowing anything about T.
Those "axioms" may a bit too specific and already locks the design into something sub-optimal. I think it would be better to specify design requirements that better show what issues need to be handled. My orthogonal const proposal would handle most of those without problem, and does away with the overlapping nature of const/invariant. It certainly handles 1,2,3,4. 5 is fulfilled subject to my interpretation. They key issue is separating what is constant from the access mode associated with pointers, references and other views. The old "invariant" just means a view of constant data. You know the data is constant and are therefore able to make use of that in optimizations and other cases. Separating those two aspects makes everything fall out simple and consistent: == "Constness" The keyword const would mean "constant" and the meaning is the established one that the compiler may rely on. Constant refers to the actual data (binary representation). Constant variables may not be changed after initialization. = Plain old data A constant (non-manifest versions): const int a = 5; const int b = runtimeFunction(); // Ok const int c = rand(); // Ok The constness of those are a part of their type, so typeof(a) == const(int). A struct with constant members becomes non-assignable (but copyable): struct S { const int a; int b; } The const member has to be initialized at struct initialization. A a = S(1,2); // Ok A b = a; // Ok a = b; // Error: assignment to a constant a.b = b.b; // Ok const S c = S(1,2); // Ok c.b = b.b; // Error = Pointers/Arrays A pointer and array slice to/of constant data: const(int) *a; const(int) a[]; A constant pointer to an int: int x; const int y; const int* a = &x; // Ok *x = 5; // Ok a++; // Error: modifying a constant const int* b = &y; // Error: incompatible types *b = 5; // Ok const(int) *c = &y; c++; // Ok (*c)++; // Error: modifying a constant const const(int) *d = &y; // A constant pointer to a constant int d++; // Error: modifying a constant = Function arguments void foo(ref const(int) x) { x = 5; // Error: modifying a constant } The constness becomes part of the type and const(int)* is not convertible to int*, nor vice versa. Apart from classes, that I will return to later, that is about all there is to say about const. == Access modes: Read only views While const above refers to the modifiability of the actual data, the read-only part refers to the access attributes of a reference. I will use the keyword "in" to mean read-only below, but please substitute with your favorite keyword. (Such as "read", "readonly", "protected" "view", etc) int x; const int y; in int * a = &x; // Ok *a = 5; // Error: No write access in int * b = &y; // Ok *b = 5; // Error: No write access in const(int) * c = &x; // Error: x is not constant in const(int) * d = &y; // Ok typeof(&x) == int * typeof(&y) == in const(int) * so "in const(int) *" is implicitly convertible to "in int *", but not the other way around. Note that the read-only access modifier is implicit in pointers to constant data. Applying the read-only property to a type means all members of the type are read-only: Struct S { int *a; int b; } in S s; s.b = 5; // the read-only part doesn't refer to the actual data, // just the access through references s.a = &x; // Ok; *s.a = 5; // Error: No write access though S An array slice behaves identical to the struct S above. in int[] t; t = &x[0..1]; // Ok t[0] = 5; // Error: No write access though S There is a wish to make the read-only property transitive, which means that applying the read-only property to a type means that all types referred to by the type also gets the read-only property: int *m = &x; // Ok in int **b = &m; // Ok **b = 5; // Error, since typeof(*b) == in int *m Everything is nice and consistent so far. The remaining parts are A) member functions and B) classes. == Member functions. Member functions (methods) are called though a reference. If that reference only has read-only access, only such member functions are allowed to be called. No changes here. Transitivity of the read-only propert will have to be handled manually. Something like: struct Array(T) { T[] arr; accessof!(this) T get()(int i) { return arr[i]; } static if (!is(T == const)) { void set(int i, ref T v) { arr[i] = v; } } } Array!(int); Array!(int *); Array!(const int); // <- This is the "invariant" case == Classes Since classes don't have a value type, it is not possible to define constant classes. I have two views on this. You could come up with a syntax that makes it possible to declare a type that is a reference to a constant class, but it seems to me that most classes that are meant to be constant have to be designed specifically for this purpose, so I propose making the constant a part of the class declaration: const class String { this(char[] data) {...} ... } For classes that support both a modifiable and a constant mode, and the constant mode is important enough to let the compiler know about, one could define: const class ConstString : MutableString { // any non-read-only method of the superclass // is blocked ... } Classes are special beasts that have other was to do access control (a read only view interface for instance). To end, I'd be very interested in hearing what the issues with this design are and what unspoken design requirements this fails to fulfill. -- Oskar
Dec 09 2007
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Gregor Richards wrote:
 Not a single person on this board (and I mean NO ONE) has a grasp over 
 everything that one can reasonably expect const to do. What we need to 
 do is construct a complete list of features that the const system ought 
 to have, so that any const proposal can be checked against the "good 
 clean const fun" checklist. Instead, what we have is suggestion after 
 suggestion, each with good points but each with fundamental flaws. We're 
 never going to get anywhere like this because nobody knows what everyone 
 needs.
 
 Disclaimer: It is of course impossible to make a list that makes 
 everyone happy. C'est la vie.
 
  - Gregor Richards
Okay, I'll throw my hat into the ring. The most paramount requirement of const for me is _ignorability_. That is, if I don't want to use const or think about const, or even understand const, that should be mostly possible.
Dec 07 2007