tail const

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sat Dec 4 19:37:29 PST 2010


On 12/4/10 3:19 PM, Michel Fortin wrote:
> On 2010-12-04 11:06:14 -0500, Andrei Alexandrescu
> <SeeWebsiteForEmail at erdani.org> said:
>
>> On 12/4/10 9:58 AM, Michel Fortin wrote:
>>> On 2010-12-04 08:55:19 -0500, Andrei Alexandrescu
>>> <SeeWebsiteForEmail at erdani.org> said:
>>>
>>>> If conversion is allowed only for values (i.e. perform a memberwise
>>>> copy of one struct to another), it looks like things could work.
>>>> Almost. The problem is that that surreptitious copy completely
>>>> bypasses the constructor:
>>>>
>>>> struct A(T) {
>>>> private T obj;
>>>> private bool isObject;
>>>> this(T obj_) {
>>>> obj = obj_;
>>>> static if (is(T == Object)) isObject = true;
>>>> }
>>>> }
>>>>
>>>> auto a = A!Widget(new Widget);
>>>> A!Object b = a; // works, new automatic conversion rule
>>>> assert(!b.isObject); // passes, invariant is messed up
>>>
>>> Copying a struct always bypasses the constructor, whether it's a
>>> template or not.
>>
>> That's not copying, it's moving, and it always preserves type.
>>
>>> If you want to maintain invariants, add the
>>> "this(this)" postblit constructor.
>>
>> The postblit constructor assumes the source and target types are the
>> same.
>>
>>> Your invariant in the case above is a
>>> little silly since it stores a value deduced from the template parameter
>>> as a member variable. But if it's that important, fixing it is trivial:
>>> add a postblit constructor.
>>>
>>> this(this) {
>>> static if (is(T == Object)) isObject = true;
>>> else isObject = false;
>>> }
>>
>> The problem is the default and implicit behavior is broken.
>
> Well, sometime this assumption is also barrier that gets in the way.
> I'll concede to you that it might not be desirable to allow this in all
> cases and we might need a way to opt-in or opt-out of this.
>
>
>>> I'm not sure why you imply it won't work for references. That's the
>>> whole point of the proposal. It can work for references as long as the
>>> memory layout is the same and each member can also be converted as a
>>> reference.
>>
>> No. For references to work with mutable objects, you need
>> equivariance, not contravariance. It's a classic.
>
> Perhaps you should stop misinterpreting.

In fairness you changed the approach.

> Where did I say that references
> would have to work with *mutable* objects?
>
> struct A(T) {
> T obj;
> }
>
> Now, if you have a reference to "A!Widget", it's true that you can't
> convert it to a reference to "A!Object". What you could do however is
> convert it to a reference to "A!(const(Object))". The compiler would
> have to transitively check whether each member of the original can be
> converted by reference to their new type before allowing the conversion.

Nagonna work. Any method inside A assumes certain types, you can't 
simply change all field types and just assume that methods will continue 
to work as intended, even if they still compile.

I would agree such a rule works with a simple, controlled record type 
such as Tuple.


Andrei


More information about the Digitalmars-d mailing list