[DISCUSS] trait behavior with instance and static methods of otherwise same signature

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

[DISCUSS] trait behavior with instance and static methods of otherwise same signature

paulk_asert

There are some trait edge cases which I think we can improve.

If I have a trait and override by a method in my class
with the same signature except static, e.g.:

trait Foo { def foo() { 'foo' } }
class FooImpl implements Foo {
    static foo() { 'bar' }
}
assert new FooSFoo().foo() == 'bar'

you currently get an error message like:

The method 'java.lang.Object foo()' is already defined in class 'FooImpl'.
You cannot have both a static and an instance method with the same signature

This seems okay to me although perhaps could be made clearer
by detecting during trait composition rather than being caught during
later verification.

However, for the case where the trait has the static method
and I override with an instance method, e.g.:

trait SFoo { static foo() { 'sfoo' } }
class SFooImpl implements SFoo {
  def foo() { 'baz' }
}
assert new SFooImpl().foo() == 'baz'

It currently passes. I would expect that to be an error.
The standard rule is the implementation within the class
wins if one is found matching a trait but is it really a match?

Similarly, this passes:

class SFooFoo implements SFoo, Foo {}
assert new SFooFoo().foo() == 'foo'

but this fails:

class FooSFoo implements Foo, SFoo {}
assert new FooSFoo().foo() == 'sfoo'

with:

The method 'java.lang.Object foo()' is already defined in class 'FooSFoo'.
You cannot have both a static and an instance method with the same signature
 at line: -1, column: -1

I would expect both to fail. The standard rule is that the last one wins if there
are more than one of the same signature but I am not sure you can treat these
as matching signatures.

 What do others think? 
 
Cheers, Paul.

Reply | Threaded
Open this post in threaded view
|

Re: [DISCUSS] trait behavior with instance and static methods of otherwise same signature

eric.milles

Shouldn't an instance method always win out over a static method?  I too would always expect a compile error for attempting to override static with instance method or vice-versa.


What would/should happen if trait adds method in future that is in conflict with legal compiled state of implementing class?

Reply | Threaded
Open this post in threaded view
|

Re: [DISCUSS] trait behavior with instance and static methods of otherwise same signature

Jochen Theodorou
In reply to this post by paulk_asert
On 03.08.2018 16:31, Paul King wrote:
[...]

> However, for the case where the trait has the static method
> and I override with an instance method, e.g.:
>
> trait SFoo { static foo() { 'sfoo' } }
> class SFooImpl implements SFoo {
>    def foo() { 'baz' }
> }
> assert new SFooImpl().foo() == 'baz'
>
> It currently passes. I would expect that to be an error.
> The standard rule is the implementation within the class
> wins if one is found matching a trait but is it really a match?

well, since Java8 we have static methods in interfaces:

> public interface X { static int foo(){return 1;}}
> class Y implements X {
>   public int foo() { return 2;}
>   public static void main(String[] args) {
>     System.out.println(new Y().foo());
>   }
> }

this will return 2, so I would say Groovy is doing the right thing here.

> Similarly, this passes:
>
> class SFooFoo implements SFoo, Foo {}
> assert new SFooFoo().foo() == 'foo'
>
> but this fails:
>
> class FooSFoo implements Foo, SFoo {}
> assert new FooSFoo().foo() == 'sfoo'
>
> with:
>
> The method 'java.lang.Object foo()' is already defined in class 'FooSFoo'.
> You cannot have both a static and an instance method with the same signature
>   at line: -1, column: -1
 >> I would expect both to fail. The standard rule is that the last one
wins
> if there
> are more than one of the same signature but I am not sure you can treat
> these
> as matching signatures.

my expectation is that the static method exists on the interface only.
And this means both should work.

bye Jochen
Reply | Threaded
Open this post in threaded view
|

Fwd: [DISCUSS] trait behavior with instance and static methods of otherwise same signature

paulk_asert

Oops, didn't forward to list. I created this issue:
To track whether we can fix as per Jochen's suggestion.
I.e. more like Java (albeit accounting for Groovy's different approach).

Paul.


---------- Forwarded message ---------
From: Paul King <[hidden email]>
Date: Sat, Aug 4, 2018 at 7:53 AM
Subject: Re: [DISCUSS] trait behavior with instance and static methods of otherwise same signature
To: Jochen Theodorou <[hidden email]>




On Sat, Aug 4, 2018 at 1:58 AM Jochen Theodorou <[hidden email]> wrote:
On 03.08.2018 16:31, Paul King wrote:
[...]
> However, for the case where the trait has the static method
> and I override with an instance method, e.g.:
>
> trait SFoo { static foo() { 'sfoo' } }
> class SFooImpl implements SFoo {
>    def foo() { 'baz' }
> }
> assert new SFooImpl().foo() == 'baz'
>
> It currently passes. I would expect that to be an error.
> The standard rule is the implementation within the class
> wins if one is found matching a trait but is it really a match?

well, since Java8 we have static methods in interfaces:

> public interface X { static int foo(){return 1;}}
> class Y implements X {
>   public int foo() { return 2;}
>   public static void main(String[] args) {
>     System.out.println(new Y().foo());
>   }
> }

this will return 2, so I would say Groovy is doing the right thing here.

> Similarly, this passes:
>
> class SFooFoo implements SFoo, Foo {}
> assert new SFooFoo().foo() == 'foo'
>
> but this fails:
>
> class FooSFoo implements Foo, SFoo {}
> assert new FooSFoo().foo() == 'sfoo'
>
> with:
>
> The method 'java.lang.Object foo()' is already defined in class 'FooSFoo'.
> You cannot have both a static and an instance method with the same signature
>   at line: -1, column: -1
 >> I would expect both to fail. The standard rule is that the last one
wins
> if there
> are more than one of the same signature but I am not sure you can treat
> these
> as matching signatures.

my expectation is that the static method exists on the interface only.
And this means both should work.

Currently for traits we don't put static methods in any interface (pre-JDK8 doesn't
have static methods in interfaces), so it only gets weaved directly into the class.
So we have different behavior to Java here. For me though, the current
behavior brings in the static method even if an instance method with the same
signature exists. We have labelled static methods as experimental but this seems
like a case we need to fix.

I have similar questions wrt final methods but I'll ask those in another email.

 

bye Jochen
Reply | Threaded
Open this post in threaded view
|

Re: [DISCUSS] trait behavior with instance and static methods of otherwise same signature

paulk_asert

After analysis, I ended up leaving the existing behavior but just improved the error message
for the failing cases. We already have Java-like behavior for some cases.
The rules around trait composition keep processing simple, e.g. for multiple inheritance
conflicts, the last found trait is favored. So TraitComposer can decide whether to weave
in a method just by looking at the trait and the existing methods since we traverse traits
in reverse order. Making this process much more complex didn't seem warranted
to try to make ourselves more Java like for the other cases. I think the error messages
will make it clear what is going on.

Cheers, Paul.


On Sat, Aug 4, 2018 at 9:42 PM Paul King <[hidden email]> wrote:

Oops, didn't forward to list. I created this issue:
To track whether we can fix as per Jochen's suggestion.
I.e. more like Java (albeit accounting for Groovy's different approach).

Paul.


---------- Forwarded message ---------
From: Paul King <[hidden email]>
Date: Sat, Aug 4, 2018 at 7:53 AM
Subject: Re: [DISCUSS] trait behavior with instance and static methods of otherwise same signature
To: Jochen Theodorou <[hidden email]>




On Sat, Aug 4, 2018 at 1:58 AM Jochen Theodorou <[hidden email]> wrote:
On 03.08.2018 16:31, Paul King wrote:
[...]
> However, for the case where the trait has the static method
> and I override with an instance method, e.g.:
>
> trait SFoo { static foo() { 'sfoo' } }
> class SFooImpl implements SFoo {
>    def foo() { 'baz' }
> }
> assert new SFooImpl().foo() == 'baz'
>
> It currently passes. I would expect that to be an error.
> The standard rule is the implementation within the class
> wins if one is found matching a trait but is it really a match?

well, since Java8 we have static methods in interfaces:

> public interface X { static int foo(){return 1;}}
> class Y implements X {
>   public int foo() { return 2;}
>   public static void main(String[] args) {
>     System.out.println(new Y().foo());
>   }
> }

this will return 2, so I would say Groovy is doing the right thing here.

> Similarly, this passes:
>
> class SFooFoo implements SFoo, Foo {}
> assert new SFooFoo().foo() == 'foo'
>
> but this fails:
>
> class FooSFoo implements Foo, SFoo {}
> assert new FooSFoo().foo() == 'sfoo'
>
> with:
>
> The method 'java.lang.Object foo()' is already defined in class 'FooSFoo'.
> You cannot have both a static and an instance method with the same signature
>   at line: -1, column: -1
 >> I would expect both to fail. The standard rule is that the last one
wins
> if there
> are more than one of the same signature but I am not sure you can treat
> these
> as matching signatures.

my expectation is that the static method exists on the interface only.
And this means both should work.

Currently for traits we don't put static methods in any interface (pre-JDK8 doesn't
have static methods in interfaces), so it only gets weaved directly into the class.
So we have different behavior to Java here. For me though, the current
behavior brings in the static method even if an instance method with the same
signature exists. We have labelled static methods as experimental but this seems
like a case we need to fix.

I have similar questions wrt final methods but I'll ask those in another email.

 

bye Jochen