September 10, 2007
Derek Parnell wrote:
>> o  const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":
> 
> Remind me again what the difference between 'const' and 'invariant' is.

const: I promise not to change this, but acknowledge that somebody else might.

invariant: Neither I nor anyone else will change this.

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.

 - Gregor Richards

PS: Or at least, this is my understanding :)
September 10, 2007
Walter Bright escribió:
> 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.
> 
> Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal.
> 
> 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)
> 
> The insights they came up with were:
> 
> 1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary.
> 
> 2) tail const can be handled in other ways, read on
> 
> So, what we are left with is:
> 
> o  no more final
> 
> 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
> 
> o  const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int).
> 
> o  tail invariant for an array or pointer type can be done using the existing syntax:
> 
>  invariant(char)[] s;   // string, i.e. an array of invariant chars
>  const(T)* p;  // pointer to tail const T
> 
> 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.
> 
> o  it will be illegal to attempt to change the key value of a foreach loop, but the compiler will not be able to diagnose all attempts to do so
> 
> o  static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time.
> 
> o  no initializer means it is assigned in the corresponding constructor.
> 
> o  const/invariant declarations will always allocate memory (so their addresses can be taken)
> 

I won't comment on all that since I'm still lost in all that const thing. But...

> o  So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that:
> 
>     macro x = 3;
>     macro s = "hello";

Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks.

-- 
Carlos Santander Bernal
September 10, 2007
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(...))
September 10, 2007
Carlos Santander wrote:
> Walter Bright escribió:
>> o  So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that:
>>
>>     macro x = 3;
>>     macro s = "hello";
> 
> Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks.
> 

Seems to me like this unnecessarily departs from the macro syntax introduced at the conference:

macro foo(e) { e = 3; }

(On the other hand, in one of them the macro is for an expression while in the other one it's a sequence of declarations/statements.  So maybe it is reasonable to have the different syntax.)

Thanks,
Nathan Reed
September 10, 2007
Walter Bright wrote:
> (snip)
> o  static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time.

I'd like to suggest that we use some keyword other than "static."  Yeah, I know that "static" can imply "static analysis" (compile time), but the static modifier on a variable has a well-known meaning from C: it's not exported.  I think that that was a poor design choice in C, but now we're stuck with millions of programmers who expect it.

I think that this would just cause confusion, and perhaps we need a new keyword to express this new concept.  While I understand that we don't want to multiply keywords, multiplying concepts, and then overloading them all into a single keyword, is, IMHO, even worse.

> o  no initializer means it is assigned in the corresponding constructor.
> 
> o  const/invariant declarations will always allocate memory (so their addresses can be taken)
> 
> o  So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that:
> 
>     macro x = 3;
>     macro s = "hello";

How about "inline"?  That seems to clearly express what we want to express (there is a clear parallel between inline functions and inline constants).

I don't recall: is inline a keyword in D or not?
September 10, 2007
Derek Parnell wrote:
> On Mon, 10 Sep 2007 12:15:09 -0700, Walter Bright 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

So then it would be ok to completely overrwrite an S, but not to set it's only member directly?
alias S!(const(int)) T;
T a;
T b;
a = b;  // ok??
a.member = b.member; // not ok??

It seems a little odd since they do exactly the same thing.
Hopefully copying a struct will be treated the same as elementwise copying of the members (so both should be illegal above).

> But most structs contain multiple members, and usually of different types.

Probably someone clever will create a type-constructor template that generates constified version of a given struct type using __traits or something.  Then you'll just do

   alias MakeConst!(MyStruct) MyConstStruct;

If not, we'll just keep pestering Walter until it is possible to write such a template. :=)

Probably more realistic is a case where you want to switch between
struct T { int* x; int y; }
and
struct T { const(int)*; int y; }

So the const doesn't start on the member level, but stuff-pointed-to-by-members level

--bb
September 10, 2007
On 9/10/07, Russell Lewis <webmaster@villagersonline.com> wrote:

> the
> static modifier on a variable has a well-known meaning from C: it's not
> exported.

We use private for that purpose in D, so static is free to be retooled to mean "compile-time".
September 10, 2007
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.
> 
> Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal.
> 
> 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)

Does c) include being able to pass literal arguments to functions expecting const-references?  I.e. sort of the opposite: being able to treat value types as const-references, even though they are const values.

> 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

I'm very happy that 'const int' will mean something other than 'just plain int'.  The always-off-by-one part of the current design is hard to get enthusiastic about.  But this one makes more sense.

Maybe you might consider Janice's suggestion for the structs, though:

const(S)* // Pointer to S nonconst, S is const
const(S)  // S const
const*(S)  // S nonconst, but stuff accessed via S is const
const**(S)  // S and S.member nonconst, but stuff accessed via S.member
is const

--bb
September 10, 2007
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
September 10, 2007
Nathan Reed wrote:
> Carlos Santander wrote:
>> Walter Bright escribió:
>>> o  So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that:
>>>
>>>     macro x = 3;
>>>     macro s = "hello";
>>
>> Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks.
>>
> 
> Seems to me like this unnecessarily departs from the macro syntax introduced at the conference:
> 
> macro foo(e) { e = 3; }
> 
> (On the other hand, in one of them the macro is for an expression while in the other one it's a sequence of declarations/statements.  So maybe it is reasonable to have the different syntax.)

It's not far off from things used in some functional programming languages, so it doesn't look to bad to me.  The word 'macro' typically implies a direct, maybe even textual, substitution.  It's also a lot like #define, just with an '=' there which I think is an improvement over #define.  '=' for the no-arg macros, '{ }' for the arg-ful macros.  Seems ok to me.

--bb