Re: Covariant Return Types

[email protected] Tue, 24 Feb 2004 18:48:36 -0600
Newsgroups gmane.comp.lang.nice.general
Message-ID <[email protected]>
Quoting Arjan Boeijink <[email protected]>:

> > Now, how many =self= methods do we have? One method with two
> > implementations? Or two methods, with the first one having two
> > implementations and the second one having one implementation.
> 
> From typechecking / resolving point of view there are 2 methods
> but for dispatching it's one method.

Let's ask the question a different way. If I have:

    package a;
    class A { }
    class B extends A { }
    A self(A a) = a;
    B self(B b) overrides A self(A) = b;

    void main(String [] args) {
        let x = self(A); // syntax?
        let y = self(B); // syntax?
        println(x == y); 
    }

Do I get "true" or "false"? If it is "true" then I would say there is one method
and if it is "false" I would say there are two methods. This is mostly just a
terminology thing though.


> >If so, it isn't much different than:
> >    package a;
> >    public class A { }
> >    public class B extends A { }
> >    public A self(A a);
> >           B anothername(B b) overrides A self(A a);
> >    self(A a)        { log("A -> A"); return a; }
> >    anothername(B b) { log("B -> B"); return b; }
> >That is, allowing specialization of a method by another method that doesn't
> even
> >have the same name.
> 
> This would be doable but it will yield new problems for example adding an
> implementation like:
>   self(B a) { return new A(); }

It doesn't introduce any new problem that I see. The error would be:
    line 7, column 1: Ambiguity for method examples.A self(A a)
    both line 10, column 1: self([email protected])
    and  line 9, column 1: anothername([email protected])
    match for parameters of type (examples.B).
vs.
    line 7, column 1: Ambiguity for method examples.A self(A a)
    both line 10, column 1: self([email protected])
    and  line 9, column 1: self([email protected])
    match for parameters of type (examples.B).
It could also come in handy for cases where the method we want to override is
already overloaded (see below).

> >Do we want clients of this package to know that the second implementation
> >even exists?
> 
> If the client can add implementations for that method it needs to know which
> implementations exist.
> When adding  self(B a) { ... }  in the client package the compiler will give
> an ambiguous implementation error at coverage testing.

So, then we can conclude that visibility modifiers only make sense for method
declarations, not for method implementations, right? So that:
    public  A self(A a) { ... }
    private   self(B b) { ... }
should be disallowed, the correct syntax would be:
    public  A self(A a) { ... }
              self(B b) { ... }

> >I guess this doesn't work in cases where the method we want to override has
> >already been overloaded:
> >
> >    package c;
> >    class A { }
> >    A doSomething(A a) { ... }
> >
> >    package d;
> >    import c;
> >    void doSomethingElse(A a) { ... }
> >
> >    package e;
> >    import c;
> >    void doSomethingElse(A a) { ... }
> >
> >    package f;
> >    import c;
> >    import b;
> >    import c;
> >    class B extends A { }
> >    B doSomething(B a) { ... }
> >    doSomethingElse(B b) { ... }
> >

> > Similarly, we should be able to say whether f.doSomethingElse(B)
> >is a specialization of d.doSomethingElse(a) or e.doSomethingElse(A).
> 
> Yes, maybe using the fully qualified method name for that like:
>    d.doSomeThingElse(B b) { ... }

Okay, but try this version:

    package c;
    interface A { }
    interface B { }
    A doSomething(A a) { ... }
    B doSomething(B b) { ... }

    package d;
    import c;
    class C implements A, B { }
    override c.doSomething(C a) { ... }

Now, does d.doSomething(C) override c.doSomething(A) or c.doSomething(B)? Notice
in the old specialization syntax, the last line would be:
    override c.doSomething(a@C);
And then, we could generalize the syntax to:
    override c.doSomething(A a@C);
which would make it obvious that we are specializing c.doSomething(A).

Also, notice that when the package name is long, it is ugly to provide many
specializations using that syntax.

> > But, should we be able to say that f.doSomethingElse(B) is a specialization
> of _both_?:
> >     doSomethingElse(B b) overrides d.doSomethingElse(A),
> >                                    e.doSomethingElse(A) { ... }
> Maybe, but first we need to look at how useful this is in practice. And what
> about the reversed case, where a new definition is a generalization of one or
> more methods?

I agree, maybe it is not useful. Your idea is very interesting, I never even
considered that. Can you think of a useful example? 

> >Another case is specialization by value:
> I think this is not useful enough to justify making the type system more
> complex.

I agree. Would this be a proper description of the (future) method model in Nice?:

Every method has exactly one type and zero or more implementations. A method can
be specialized by other methods; when this is done, the implementations of all
the specializing methods are considered also to be implementations of the
specialized method. For a method M to be specialized by a method N, for every
nth parameter P(M,n) and P(N,n), it must be true that P(M,n) : T, P(N,n) : U
implies U <: T, and if V and W are the return types of M and N, respectively,
then W <: T. Methods are dispatched to a particular implementation based on the
types and/or values of the actual parameters. 

This leaves syntactical issues aside, including whether or not M and N have to
have the same local name.

- Brian




-------------------------------------------------------
SF.Net is sponsored by: Speed Start Your Linux Apps Now.
Build and deploy apps & Web services for Linux with
a free DVD software kit from IBM. Click Now!
http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click