tail const

Fawzi Mohamed fawzi at gmx.ch
Sat Dec 4 15:39:18 PST 2010


On 4-dic-10, at 02:26, Steven Schveighoffer wrote:

> On Fri, 03 Dec 2010 19:06:36 -0500, Andrei Alexandrescu <SeeWebsiteForEmail at erdani.org 
> > wrote:
>
>> On 12/3/10 5:17 PM, Steven Schveighoffer wrote:
>>> On Thu, 02 Dec 2010 17:02:42 -0500, Michel Fortin
>>> <michel.fortin at michelf.com> wrote:
>>>
>>>> On 2010-12-02 16:14:58 -0500, "Steven Schveighoffer"
>>>> <schveiguy at yahoo.com> said:
>>>>
>>>>> On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin
>>>>> <michel.fortin at michelf.com> wrote:
>>>>>> My only concern with the "const(Object)ref" syntax is that we're
>>>>>> reusing 'ref' to denote an object reference with different
>>>>>> properties (rebindable, nullable) than what 'ref' currently  
>>>>>> stands
>>>>>> for. But it remains the best syntax I've seen so far.
>>>>> Where it would be beneficial is in mimicking the tail-const
>>>>> properties of arrays in generic ranges.
>>>>> I have a container C, which defines a range over its elements R.
>>>>> const(R) is not a usable range, because popFront cannot be  
>>>>> const. So
>>>>> now I need to define constR, which is identical to R, except the
>>>>> front() function returns a const element.
>>>>> So now, I need the same for immutable.
>>>>> And now I need to triplicate all my functions which accept the
>>>>> ranges, or return them.
>>>>> And I can't use inout(R) as a return value for ranges.
>>>>> If you can solve the general problem, and not just the class
>>>>> tail-const, it would be hugely beneficial.
>>>>> My thought was that a modifier on const itself could be stored  
>>>>> in the
>>>>> TypeInfo_Const as a boolean (tail or not), and the equivalent  
>>>>> done in
>>>>> dmd source itself.
>>>>
>>>> I'm not sure I get the problem. Can you show me in code?
>>>
>>> Here is an example range from dcollections (well, at least the  
>>> pertinant
>>> part), for a linked list:
>> [snip analysis]
>>> @tail inout(Range) opSlice() inout
>>> {
>>>  ...
>>> }
>>
>> I was about to post a similar analysis, but my suggested conclusion  
>> is very different: in my humble opinion, we must make-do without  
>> tail const. We can't afford to inflict such complexity on our users.
>
> BTW, even though I conceed that my ideas are too complex to be worth  
> using, I don't agree we must "make-do" without tail-const.  We just  
> need to find a different way to solve the problem.  Let's talk about  
> how we could add some sort of custom implicit casting to the type- 
> system.  And actually, we need implicit lvalue casting (because all  
> member functions have ref this).

I fully agree with this.
I will try to recap what I think is the most clean solution from the  
conceptual point of view, then maybe others have an idea on how to  
find a good solution that is not too difficult to implement, and  
doesn't break what was said in TDPL too much.

The current const implies that the references to that type have to be  
constant.

tail const, and has the recursive definition I had given:
valueConst(T) is
	T for basic types functions and templates
	refConst(U)* if is(T U==U*)
	refConst(U)[] if is(T U==U[])
	V if is(T == struct), where V is a structure just like T, but where  
each of its fields is tail const

tail const marks all that is copied when one assigns T v2=v1; as  
mutable.
Indeed to protect v1 it is not needed to protect the values that get  
copied in the assignment, those values can be changed without changing  
v1.
For this reason tail const is the most weak const that one can have in  
pure functions, in ideally should mean tail const (thus in some way  
tail const comes from the protection of a starting const.

any lvalue by default should be tail const, if it was const, and tail  
immutable if it was immutable, but is implicitly convertible to full  
const/immutable.

in a way tail const is more fundamental as it is the least protection  
that one has to give to protect some data owned by others.
	
If I have a global variable the current const/immutable can guarantee  
that its value will not change, while tail immutable guarantees that  
one can safely point to that data as it won't be changed: that data  
can be shared safely (not necessarily by several threads, even simply  
by several objects).

Thus both have their function, but in general I think that tail const  
might be even more important (if I had to choose one const/immutable  
type I would choose the tail one).


More information about the Digitalmars-d mailing list