Oskar's const proposal

Oskar Linde oskar.lindeREM at OVEgmail.com
Sat Jan 5 04:23:13 PST 2008


Bill Baxter wrote:
> Oskar Linde wrote:
>  > Walter Bright wrote:
>  >> Janice Caron wrote:
>  >>> On 12/28/07, Walter Bright <newshound1 at digitalmars.com> wrote:
>  >>>> Janice Caron wrote:
>  >>>>> y is a /copy/ of x, and clearly it should be possible to make a copy
>  >>>>> of a const thing and have the copy be mutable.
>  >
>  > *BEEP* Confusion warning: you mean *constant*, not "const". Huge
>  > difference. :)
>  >
>  >>>> That doesn't work for structs or classes.
>  >>>
>  >>> It doesn't? For structs
>  >>>
>  >>>     struct S {}
>  >>>     const S x;
>  >>>     auto y = x;
>  >>
>  >> Imagine you have:
>  >>     struct S { int* p; }
>  >> Because const is transitive, const(S) implies that now p points to
>  >> const. But if you strip off the const in the assignment, you've lost
>  >> the const-ness of p, and now you have a gaping hole in the
>  >> const-correctness.
>  >
>  > The problem with the current const in D is the lack of orthogonality. As
>  > far as I can see, those problems would be solved by my orthogonal const
>  > proposal posted earlier. Constant values (such as structs) are by their
>  > nature always implicitly convertible to mutable values (worst case: just
>  > make a copy).
>  >
>  > The problem with the current const iteration is that there is no way to
>  > separate the orthogonal concepts constness (as in constants) from
>  > read-only access of references.
>  >
>  > Also, as far as I can see (not very) there would also not be any need
>  > for a third type of constant (the manifest one).
>  >
>  > const int x = 5;
>  >
>  > could behave like a template and only be instantiated when the address
>  > of x is taken.
>  >
>  > The result would be a const design, equally powerful but without
>  > spoiling the beauty and simplicity of the D1.0 const. In D1.0, when
>  > something is *constant*, you simply declare it as const:
>  >
>  > struct T {
>  >     const int a = 5;
>  >     int b;
>  > }
>  >
>  > static assert(T.sizeof == int.sizeof);
>  >
>  > No need to stop and think. In D2.0 it seems like you have to go through:
>  > "Hmm, this value will never change. I will mark it as const.... no wait
>  > invariant... or maybe manifest constant using the enumeration hack?"
>  >
> 
> (Referring to http://www.csc.kth.se/~ol/const.pdf in comments below that 
> mention "your proposal")
> 
> I think everyone has trouble seeing how your const proposal fixes the 
> tricky issues.  You give some syntaxes but don't show how they solve the 
> problems that have caused all the consternation (!) over the past year 
> that arise when you start pulling on the string. 

I can't say it fixes all tricky issues, and since I have no full grasp 
of what all the tricky issues are I regret calling it a proposal. Let's 
just consider it a thought experiment.

> Also your comparison 
> table doesn't include structs, which seems a big omission since structs 
> often end up causing the trouble with const proposals.  Also it would be 
> helpful if your table gave an brief description of the behavior of each 
> row: like "in int*: the pointer can be modified but the int cannot via 
> this pointer"

More on that below.

> But anyway, if I understand from the brief description, the idea is 
> basically to use "const" to apply to values only and to mean the value 
> will not change, period, no way, never.  And you use 'in' exclusively 
> for things that can refer to other memory to say "you can't change what 
> it refers to through this reference".
> 
> Ok, that sounds pretty neat.

It does, doesn't it? My main gripe with the design of the current const 
is that the meanings of invariant and const are too overlapping 
(non-orthogonal if you wish). A plain int can have three different types:

int
const int
invariant int

Where the latter two are almost (but not fully) identical. There are 
other ways to resolve this, but for now I will focus on orthogonalizing 
the concepts.

Plain old data would only come in two flavors: variable and constant. 
The "plain" data types are:
* all primitive non-reference types (int,float,char,...)
* structs and unions containing only plain data types.

> So first question is: what happens when you use "in" on a plain int?  It 
> isn't a reference of any kind so is "in int" an error or a no-op?

Both behaviors are possible, but I think making it a no-op is the most 
helpful one. The result in either case is that nothing could ever have 
the type "in int".

> Does it have to be "const const(int)*"?  Seems like that should be the 
> same as "const(int*)".  It's unclear in your proposal how const and in 
> are scoped.

If const only applies to the actual data without imposing any 
contractual limitations on what may be done with eg. a copy of the data 
we gain the neat effect of always having const T implicitly convertible 
to T. From this also follows that const (as opposed to in) has to be 
intransitive which is why I wrote "const const(int)*".

We could also consider a design where constness imposes contractual 
limitations on the data, eg. making const fully transitive, but we would 
lose the implicit const T => T conversion. This is outside the scope of 
this thought experiment, but nevertheless leads down some interesting 
paths. (*)

> I see some potential messiness given a pointer variable t of type 'T' 
> determining whether I can modify what it points to or not.  As far as I 
> can tell, T can come in 3 non-modifiable flavors:
> * "in S*" (readonly ref to mutable S),
> * "in const(int)*" (readonly ref to immutable S),
> * and "const(int)*" (mutable ref to immutable S)
> So i'd need to check if either "typeof(*t) is const" or "typeof(t) is in".

The "in" attribute of a reference could be implicit from having a 
reference to constant data. So

typeof(const(T)*) == in const(T)*

and you'd only need to check the in attribute of the type to know if you 
can modify what it refers to.

Regarding in and structs, I think it is advantageous if

T[] and
struct Slice(T) { T *ptr; size_t length; }

behaved identically with respect to a const T and an in type attribute 
which would have certain implications.

> Hope my questions are clear enough to you and give you some insight into 
> what parts of your proposal people find difficult to understand.

Thank you for the questions. They were good, although not as tricky as I 
feared (there exists tricky ones). :) I hope I managed to answer them 
and bring some clarity on the topic. At least, I hope this may 
possibilities forward for the current debacle.

-- 
Oskar



More information about the Digitalmars-d mailing list