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

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

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.

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.

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

... 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

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.

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.

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

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.

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.

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.

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.

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.

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.

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

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.