tail const

Michel Fortin michel.fortin at michelf.com
Sat Dec 4 13:19:30 PST 2010


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. 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.


-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



More information about the Digitalmars-d mailing list