Inheritance of purity

Timon Gehr timon.gehr at gmx.ch
Sat Feb 18 07:04:46 PST 2012


On 02/18/2012 03:46 PM, deadalnix wrote:
> Le 17/02/2012 03:49, Walter Bright a écrit :
>> Given:
>>
>> class A { void foo() { } }
>> class B : A { override pure void foo() { } }
>>
>> This works great, because B.foo is covariant with A.foo, meaning it can
>> "tighten", or place more restrictions, on foo. But:
>>
>> class A { pure void foo() { } }
>> class B : A { override void foo() { } }
>>
>> fails, because B.foo tries to loosen the requirements, and so is not
>> covariant.
>>
>> Where this gets annoying is when the qualifiers on the base class
>> function have to be repeated on all its overrides. I ran headlong into
>> this when experimenting with making the member functions of class Object
>> pure.
>>
>> So it occurred to me that an overriding function could *inherit* the
>> qualifiers from the overridden function. The qualifiers of the
>> overriding function would be the "tightest" of its explicit qualifiers
>> and its overridden function qualifiers. It turns out that most functions
>> are naturally pure, so this greatly eases things and eliminates annoying
>> typing.
>>
>> I want do to this for @safe, pure, nothrow, and even const.
>>
>> I think it is semantically sound, as well. The overriding function body
>> will be semantically checked against this tightest set of qualifiers.
>>
>> What do you think?
>
> Walter, I think you get the const qualifier wrong. const does not
> qualify the method, but the hidden parameter "this".
>

Conceptually, close. Effectively, no. Const methods are the only place 
in the language where 'contravariant' overrides are allowed.

> I don't think this is a good idea for const/immutable . Simply because
> you may want to have both defined, and it lead to ambiguity.
>

With the current overriding/overloading rules I see no possibility for 
ambiguity.

This is illegal:

class C{
     void foo() {}
}
class D: C{
     override void foo() {}
     void foo()const {}
}

This is unambiguous:

class C{
     void foo() {}
     void foo()const {}
}

class D: C{
     alias C.foo foo;
     override void foo() {} // overrides first overload
}

A minor issue I see:
Possible hijacking scenario:

abstract class C{
     void foo();
     void foo()const { ... }
}
class D: C{
     alias C.foo foo; // explicitly loosen hijacking prevention
     override void foo() { (cast(const)this).foo(); }
}

"we don't need a non-const overload..." =>

abstract class C{
     void foo()const { ... }
}
class D: C{
     alias C.foo foo; // explicitly loosen hijacking prevention
     override void foo() { (cast(const)this).foo(); } // foo()const hijacked
}

Error under old rules, hijacking that introduces infinite recursion 
under new rules.


> However, for pure, @safe, nothrow and basically any qualifier that
> effectively qualify the function, it is a great idea.
>

For them, it is certainly safe. It is questionable how large the 
effective benefit is for const, since the const qualifier would be 
inherited for the method only, but not for its parameters.

> BTW, to keep the source code understandable, this should be enabled only
> if the overriden keyword is present. So if you see a function with
> overriden, you'll know about thoses qualifier possibly being present. If
> the overriden isn't present, the current behaviour should be preserved.

'override' will be mandatory soon anyway.


More information about the Digitalmars-d mailing list