Gregor Richards wrote:
> const has a more limited use for optimization than invariant, since the value could be changed by other threads/programs-with-shm/whatever from under you.
const is useless for optimization, invariant is very useful for optimization. But it turns out that if you have invariant, soon you'll discover that you need const. Otherwise you'll find that every function will have to be implemented two or more times (*).
(*) Because invariants cannot be implicitly converted to mutable, and vice versa.

Gregor Richards wrote:
> Russell Lewis wrote:
>> Walter Bright wrote:
>>> What we are trying to achieve:
>>>>>> a) utility for functional programming
>>> b) better modularity by self-documenting interfaces better
>>> c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)
>>>> Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support?
>>>> Russ
> > It would probably be easy enough to add such a type modifier, but literally impossible to to hold that restriction, so I don't think it's worth it. There's no magic-bullet for concurrency.
I agree that there's no magic-bullet for concurrency, but there *are* times where it could be enforced:
1) The caller's variable is a local variable, and either there have been no pointers to the local (including frame pointers created by delegate literals), or else all of those locals were passed to external code as "const."
2) The caller already holds the variable in "exclusive" mode.
(I haven't figured out any way, yet, to make it work for globals.)
Whether it's worth the trouble is a whole 'nother question, of course.

Janice Caron wrote:
> You might want to allow
> > const(invariant(int)*)* p;
> > p is a mutable pointer to a const pointer to an invariant int.
> > Since invariant is "stronger" than const, you want to be able to do
> const(invariant(...)), but not invariant(const(...))
invariant(const(...)) will have to be accepted, and it will be treated as invariant(invariant(...)). This is just for building a type - it doesn't re-type any data.

Sean Kelly wrote:
> Walter Bright wrote:
>>>> So, what we are left with is:
>>>> o no more final
> > By this you meant that "final" in 2.0 would work exactly as in 1.0, correct?
Yes. There'll still be final classes and final virtual functions.
>> o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":
>>>> const int x = 0; // x is constant
>> const int* p = &x; // neither p nor *p can be changed
>> const(int*) p = &x; // neither p nor *p can be changed
>> const(int)* p = &x; // p can change, *p cannot be changed
> > So the presence of parenthesis would be simply to limit the extent of the type to which "const" applies?
Yes. Think of the () as presenting an 'argument' to be const-ified.
>> o tail const of a struct would have to be done by making the struct a template:
>>>> struct S(T) { T member; }
>> S!(int) // tail mutable
>> S!(const(int)) // tail const
>>>> o one can construct a template to generically produce tail const or tail invariant versions of a type.
> > Could you please explain this further? Why would templates be needed in the above two points?
Think of a struct which was your own implementation of arrays:
struct Array(T)
{
T[] a;
}
To create a tail const array, instead of const(T)[], we'd do Array!(const(T)).

Russell Lewis wrote:
> Walter Bright wrote:
>> What we are trying to achieve:
>>>> a) utility for functional programming
>> b) better modularity by self-documenting interfaces better
>> c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)
> > Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support?
That's sort of what the often proposed 'unique' type qualifier does. The problem is, there's just no reasonable way to implement it in a *checkable* manner. And if it ain't checkable, it's about as useful as painting a black stripe across your lap when driving instead of wearing a seatbelt.

On 9/10/07, Walter Bright <newshound1@digitalmars.com> wrote:
> Think of a struct which was your own implementation of arrays:
>> struct Array(T)
> {
> T[] a;
> }
>> To create a tail const array, instead of const(T)[], we'd do
> Array!(const(T)).
While that does make sense, I guess what we really want to know is why we won't be able to do this:
struct MyArray
{
int[] p;
}
and then make a tail const version with some magic keyword like
tailconst(MyArray)
That is, tailconst(T) could be some built-in keyword which created a new type which was just like T except that all its pointers would be const.
Are you saying this is such a rare thing to want to do that it's not worth supporting generically? I can't say I've ever needed it up to now.

On 9/10/07, Alexander Panek <a.panek@brainsware.org> wrote:
> What exactly is the is the difference between head and tail const?
Suppose you have a pointer to pointer to pointer to pointer to pointer to int.
(The length of this chain is irrelevant. I just threw lots in for the
hell of it).
Head const would be
const pointer to pointer to pointer to pointer to pointer to int.
Tail const would be
pointer to const pointer to const pointer to const pointer to const
pointer to const int.
Total const would be
const pointer to const pointer to const pointer to const pointer to
const pointer to const int.
i.e. head const and tail const both at the same time.

Walter Bright wrote:
> Sean Kelly wrote:
> >>> o tail const of a struct would have to be done by making the struct a template:
>>>>>> struct S(T) { T member; }
>>> S!(int) // tail mutable
>>> S!(const(int)) // tail const
>>>>>> o one can construct a template to generically produce tail const or tail invariant versions of a type.
>>>> Could you please explain this further? Why would templates be needed in the above two points?
> > Think of a struct which was your own implementation of arrays:
> > struct Array(T)
> {
> T[] a;
> }
> > To create a tail const array, instead of const(T)[], we'd do Array!(const(T)).
Okay, so basically if I want a mutable struct that may reference constant data I'll have to pass the const attribute through via a template rather than preceding the struct decl with a "tail const" keyword. Is that right? Seems fair enough. C++ requires the same approach, as far as I know.
Sean

Walter Bright wrote:
> Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.
>
Took you guys a while to figure that out... -_-'
> 1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary.
>
Then, there will no longer be a final "storage class" for var declarations?
> 2) tail const can be handled in other ways, read on
> [...]
> > o tail const of a struct would have to be done by making the struct a template:
> > struct S(T) { T member; }
> S!(int) // tail mutable
> S!(const(int)) // tail const
> > o one can construct a template to generically produce tail const or tail invariant versions of a type.
>
As Regan asked before, and how would that work for classes? This is a most fundamental issue that has not been mentioned. Without a way to declare tail const/invariant, this design, no matter how simpler or more understandable, is fundamentally *broken*.
--
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D