February 17, 2012
Jonathan M Davis wrote:
> On Thursday, February 16, 2012 18:49:40 Walter Bright wrote:
>> 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?
>
> No. Absolutely not. I hate the fact that C++ does this with virtual. It makes
> it so that you have to constantly look at the base classes to figure out what's
> virtual and what isn't. It harms maintenance and code understandability. And
> now you want to do that with @safe, pure, nothrow, and const? Yuck.

What about:

       class A { pure void foo() { } }
       class B : A { auto override void foo() { } }
February 17, 2012
Aside the fact, that it's highly ambiguous, the programmers would start forgetting to write that auto :-)

On Fri, Feb 17, 2012 at 4:35 PM, Piotr Szturmaj <bncrbme@jadamspam.pl> wrote:
> Jonathan M Davis wrote:
>>
>> On Thursday, February 16, 2012 18:49:40 Walter Bright wrote:
>>>
>>> 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?
>>
>>
>> No. Absolutely not. I hate the fact that C++ does this with virtual. It
>> makes
>> it so that you have to constantly look at the base classes to figure out
>> what's
>> virtual and what isn't. It harms maintenance and code understandability.
>> And
>> now you want to do that with @safe, pure, nothrow, and const? Yuck.
>
>
> What about:
>
>
>       class A { pure void foo() { } }
>       class B : A { auto override void foo() { } }



-- 
Bye,
Gor Gyolchanyan.
February 17, 2012
On 17 February 2012 07:42, Jacob Carlborg <doob@me.com> wrote:
> On 2012-02-17 04:15, H. S. Teoh wrote:
>>
>> On Thu, Feb 16, 2012 at 06:49:40PM -0800, Walter Bright wrote: [...]
>>>
>>> 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 like this idea.
>>
>>
>>
>>> I want do to this for @safe, pure, nothrow, and even const.
>>
>>
>> Excellent!
>>
>>
>>
>>> 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?
>>
>>
>> Semantically, it makes sense. And reducing typing is always good. (That's one of my pet peeves about Java: too much typing just to achieve something really simple. It feels like being forced to kill a mosquito with a laser-guided missile by specifying 3D coordinates accurate to 10 decimal places.)
>>
>> The one disadvantage I can think of is that it will no longer be clear exactly what qualifiers are in effect just by looking at the function definition in a derived class. Which is not terrible, I suppose, but I can see how it might get annoying if you have to trace the overrides all the way up the inheritance hierarchy just to find out what qualifiers a function actually has.
>>
>> OTOH, if ddoc could automatically fill in the effective qualifiers, then this will be a non-problem. ;-)
>
>
> And if ddoc could show the inheritance hierarchy as well.
>

Jacob++


-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
February 17, 2012
Gor Gyolchanyan wrote:
> Aside the fact, that it's highly ambiguous, the programmers would
> start forgetting to write that auto :-)

Actually you can't override an auto function so its not ambiguous. It's currently impossible to do:

override auto func() { }
February 17, 2012
This is clearly a bug, because auto is just another way of specifying a valid static type.

On Fri, Feb 17, 2012 at 5:22 PM, Piotr Szturmaj <bncrbme@jadamspam.pl> wrote:
> Gor Gyolchanyan wrote:
>>
>> Aside the fact, that it's highly ambiguous, the programmers would start forgetting to write that auto :-)
>
>
> Actually you can't override an auto function so its not ambiguous. It's currently impossible to do:
>
> override auto func() { }



-- 
Bye,
Gor Gyolchanyan.
February 17, 2012
On 02/17/2012 08:34 AM, Andrei Alexandrescu wrote:
> On 2/16/12 8:49 PM, Walter Bright wrote:
>> 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?
>
> I thought about this for a while and seems to work well. The maintenance
> scenarios have already been discussed (people add or remove some
> attribute or qualifier) and I don't see ways in which things become
> inadvertently broken.
>

I imagine that some contrived example could be deduced that uses __traits(compiles, ...) inside a pure function. But I don't think avoiding such scenarios is worthwhile.

> The const qualifier is a bit different because it allows overloading.
> Attention must be paid there so only the appropriate overload is
> overridden.
>

Introducing a new overload against const in a subclass is illegal:

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

Error: D.foo multiple overrides of same function


> Congratulations Walter for a great idea. Inference is definitely the way
> to go.
>
>
> Andrei

February 17, 2012
On 02/17/2012 02:33 PM, Timon Gehr wrote:
>
> Introducing a new overload against const in a subclass is illegal:
>
> class C{
>      void foo(){}
> }
> class D : C{
>      override void foo(){}
>      override void foo()const{}
> }
>
> Error: D.foo multiple overrides of same function

Oops...

I meant

class C{
    void foo(){}
}

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

The error message is the same though.
February 17, 2012
I think this is a current implementation problem.

In this case, just `override void foo()` in class D should override
the method in C.
And `void foo()const` should be a new overlodad of foo.

Kenji Hara

2012/2/17 Timon Gehr <timon.gehr@gmx.ch>:
> On 02/17/2012 02:33 PM, Timon Gehr wrote:
>>
>>
>> Introducing a new overload against const in a subclass is illegal:
>>
>> class C{
>>     void foo(){}
>> }
>> class D : C{
>>     override void foo(){}
>>     override void foo()const{}
>> }
>>
>> Error: D.foo multiple overrides of same function
>
>
> Oops...
>
> I meant
>
>
> class C{
>    void foo(){}
> }
>
> class D:C{
>    override void foo(){}
>    void foo()const{}
> }
>
> The error message is the same though.
February 17, 2012
Gor Gyolchanyan wrote:
> This is clearly a bug, because auto is just another way of specifying
> a valid static type.

I don't know if overriding auto makes sense at all. If you override something you should specify return type which is covariant with overrided function's one. Why would you use auto return type?

But wait... One use case where it can be helpful is overriding a function that return derived class and derived class is based on template parameter:

class A {}
class B : A {}
class C : A {}

class Test1
{
    A getA() { return new A(); }
}

class Test2(T : A) : Test1
{
    override auto getA() { return new T(); }
}

void test()
{
    (new Test2!B()).getA();
    (new Test2!C()).getA();
}

It doesn't currently compile, but if I change auto to T it does. It may be a compiler bug as you've pointed.

It's a simplified example, T may be not directly known (but still covariant to A), i.e. accesing it may be far more complex than showed by above example.

This is the only use case of override auto that come to my mind.

> On Fri, Feb 17, 2012 at 5:22 PM, Piotr Szturmaj<bncrbme@jadamspam.pl>  wrote:
>> Gor Gyolchanyan wrote:
>>>
>>> Aside the fact, that it's highly ambiguous, the programmers would
>>> start forgetting to write that auto :-)
>>
>>
>> Actually you can't override an auto function so its not ambiguous. It's
>> currently impossible to do:
>>
>> override auto func() { }
February 17, 2012
I have thought a reverse case.

class C
{
    @safe const void f(){}
}
class D : C
{
    override void f(){} // inferred as @safe const?
        // 'override' keyword must be required for override method?
    void f(){}          // @system and mutable?
        // Adding mutable version in derived class should work?
        // Does no override keyword should mean always "new root of overriding"?
}

I think the lack of 'override' keyword (filed as bug 3836) should become an error, without the phase of deprecating it. Otherwise following case will be allowed.

class C
{
    const void f(){}
}
class D : C
{
    void f(){}
        // in 2.058  Error: function test.D.f of type void() overrides
but is not
        //                  covariant with test.C.f of type const void()
        // in 2.059? overrides C.foo implicitly!!
        //   Although bug 3836 will be fixed with deprecating, -d
option allows this annoying overriding.
        //   It is worse than 2.058 and before.
}

Kenji Hara

2012/2/17 kenji hara <k.hara.pg@gmail.com>:
> I think this is a current implementation problem.
>
> In this case, just `override void foo()` in class D should override
> the method in C.
> And `void foo()const` should be a new overlodad of foo.
>
> Kenji Hara
>
> 2012/2/17 Timon Gehr <timon.gehr@gmx.ch>:
>> On 02/17/2012 02:33 PM, Timon Gehr wrote:
>>>
>>>
>>> Introducing a new overload against const in a subclass is illegal:
>>>
>>> class C{
>>>     void foo(){}
>>> }
>>> class D : C{
>>>     override void foo(){}
>>>     override void foo()const{}
>>> }
>>>
>>> Error: D.foo multiple overrides of same function
>>
>>
>> Oops...
>>
>> I meant
>>
>>
>> class C{
>>    void foo(){}
>> }
>>
>> class D:C{
>>    override void foo(){}
>>    void foo()const{}
>> }
>>
>> The error message is the same though.