You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@groovy.apache.org by Christophe Henry <ch...@c-henry.fr> on 2016/02/27 19:29:07 UTC

Inner traits?

Traits in Groovy comes as a good replacement to Java's interfaces and, 
in particular Java 8's interfaces that features default methods. Though, 
while working on a project in Groovy, I've come across a 
counter-intuitive and (AFAIK) undocumented limitation of traits: inner 
traits and access to enclosing class' variables.

The case I'm describing may be exotic and have other ways to be solved 
that I'm not aware of. In an Android application, the framework 
instanciates an Application 
<https://developer.android.com/reference/android/app/Application.html> 
object. This class can be overriden to let the developer perform 
initialization steps before the application displays (like list files). 
This Application object is (in theory) unique for an Android 
application. In order to simplify the code, I tried to make some methods 
of this class accessible to any other class implementing an inner trait. 
Here is an example:

public class CustomApplicationextends Application
{
     private static instance @Override void onCreate()
     {
         super.onCreate()
         instance =this }
     
     public trait ApplicationUtilities
     {
         public ContextgetApplicationContext(){return instance.applicationContext }
     }
}

While this piece of code would have worked with an abstract class or a 
Java 8's interface, it throws a compilation error with a trait.

I know I'm trying to do unnatural things with this language but is there 
any reason for this limitation and is there a plan to implement a 
feature like this in future releases?

Regards,
Henry Christophe

Re: Inner traits?

Posted by Jesper Steen Møller <je...@selskabet.org>.
Hi Jochen
> On 29. feb. 2016, at 12.05, Jochen Theodorou <bl...@gmx.org> wrote:
> On 29.02.2016 11:52, Jesper Steen Møller wrote:
>> Those semantics should be easy enough to cope with, if only the grammar (and taste!) would allow it.
> 
> Why does the grammar not allow it? The grammar does imho, but the later parts of the compiler are not prepared for that kind of trouble and either fail with BUG! messages (I had an NPE in one case for example) or produces code, which does not work.
Right, I actually didn’t check, just assumed is wasn’t in the grammar since it wasn’t supported (and it’s not at all supported in the Antlr4 grammar, yet).
I try not to look at groovy.g too much ;-)

-Jesper

Re: Inner traits?

Posted by Jochen Theodorou <bl...@gmx.org>.

On 29.02.2016 11:52, Jesper Steen Møller wrote:
> Hi Jochen and Henry
>
>> On 29. feb. 2016, at 11.29, Jochen Theodorou <bl...@gmx.org> wrote:
>>
>> On 27.02.2016 19:29, Christophe Henry wrote:
>> [...]
>>> public class CustomApplication extends Application
>>> {
>>>      private static instance
> […]
>>>          public ContextgetApplicationContext(){return instance.applicationContext }
>>
>> Hmmm, I wonder if this can be made sense of or not. A trait can be seen as some independent piece that can be added to a class. But for it to be independent, it cannot be non-static. In your code the trait implementation would depend on an instance of CustomApplication and cannot be created without supplying such an instance.
>
> Henry’s example refers to a static field, so it wouldn’t require the outer instance, analogous to an interface (which is static by definition).

oh... I did not see that, thanks for the clarification.

> Those semantics should be easy enough to cope with, if only the grammar (and taste!) would allow it.

Why does the grammar not allow it? The grammar does imho, but the later 
parts of the compiler are not prepared for that kind of trouble and 
either fail with BUG! messages (I had an NPE in one case for example) or 
produces code, which does not work.

All that mostly because traits have not been considered for use inside a 
class... Adding an appropriate error message for this would have been 
good. Or we go and fix it - which is not done so easily

bye Jochen

Re: Inner traits?

Posted by Jesper Steen Møller <je...@selskabet.org>.
Hi Jochen and Henry

> On 29. feb. 2016, at 11.29, Jochen Theodorou <bl...@gmx.org> wrote:
> 
> On 27.02.2016 19:29, Christophe Henry wrote:
> [...]
>> public class CustomApplication extends Application
>> {
>>     private static instance
[…]
>>         public ContextgetApplicationContext(){return instance.applicationContext }
> 
> Hmmm, I wonder if this can be made sense of or not. A trait can be seen as some independent piece that can be added to a class. But for it to be independent, it cannot be non-static. In your code the trait implementation would depend on an instance of CustomApplication and cannot be created without supplying such an instance.

Henry’s example refers to a static field, so it wouldn’t require the outer instance, analogous to an interface (which is static by definition).
Those semantics should be easy enough to cope with, if only the grammar (and taste!) would allow it.

-Jesper

Re: Inner traits?

Posted by Jochen Theodorou <bl...@gmx.org>.

On 27.02.2016 19:29, Christophe Henry wrote:
[...]
> public class CustomApplication extends Application
> {
>      private static instance @Override void onCreate()
>      {
>          super.onCreate()
>          instance =this }
>
>      public trait ApplicationUtilities
>      {
>          public ContextgetApplicationContext(){return instance.applicationContext }
>      }
> }
>
> While this piece of code would have worked with an abstract class or a
> Java 8's interface, it throws a compilation error with a trait.
>
> I know I'm trying to do unnatural things with this language but is there
> any reason for this limitation and is there a plan to implement a
> feature like this in future releases?

Hmmm, I wonder if this can be made sense of or not. A trait can be seen 
as some independent piece that can be added to a class. But for it to be 
independent, it cannot be non-static. In your code the trait 
implementation would depend on an instance of CustomApplication and 
cannot be created without supplying such an instance. If I now have a 
random class X, how can I let that use the trait without an instance of 
CustomApplication? I cannot. Then how does the instance get there? Is 
there one instance per trait usage, or do all traits share the same 
CustomApplication instance (as would be the case in the non-static case 
for inner classes!)d

So what makes no sense is to have a

class X implements CustomApplication.ApplicationUtilities {}

What could work is something like:

class X {
   def someField
   trait T {
     def getField() {return someField}
   }
   class Y implements T {
   }
   def foo(){ return new Y() }
}

def x = new X()
assert x.someField == x.foo().getField()

I kind of doubt you wanted this later version... and does not anyway... 
yes, the inner class cases have been totally ignored so far. Even making 
the trait static is raising havoc in the compiler... and that at least 
should have passed compilation and only failed when trying to access 
"someField".


Though... further thought leads me to see things a little different. In 
a trait you can do

trait X {
   def foo() { return bar }
}

class Y implements X{
   private bar = 1
}

The property bar is not existing in the trait, it is expected on 
"traited" class. Following this logic, what does it mean to access the 
field of an outer class? Strictly following this logic means not to be 
able to do that. Resolving first outer class fields and then traited 
class means to get into trouble with dynamic properties.


bye Jochen