You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by Jochen Theodorou <bl...@gmx.org> on 2016/03/30 20:48:44 UTC

Re: interface/implementation patten

On 30.03.2016 18:59, OC wrote:
> Oh, by the way,
>
> On 30. 3. 2016, at 17:12, Jochen Theodorou <bl...@gmx.org> wrote:
>> This again forces people to split their classes in interfaces and implementations
>
> reminded me another question of mine. I actually want to embrace this pattern for a long time (after all, I am used to it from ObjC), but there are two problems:
>
> (a) interfaces cannot contain static methods
>
> I am afraid there would be no solution at all in Java-based world, or does Groovy bring some?

This require support through the JVM... and actually Java8 has that... 
But I think we do not support that yet. I am unhappy about the semantics 
of static methods in general in Java and that we copied most of it in 
Groovy... extending that to interface is for me no good decision... but 
well...

> (b) they force me to maintain two parallel hierarchies, like
>
> ===
> interface Foo {
>    def foo();
>    ...
> }
> class Foo_Implementation implements Foo {
>    def foo() { ... }
>    def myfoo() { ... }
>    ...
> }
> interface Bar implements Foo {
>    def bar();
>    ...
> }
> class Bar_Implementation extends Foo_Implementation implements Bar {
>    def bar() { ... }
>    ...
> }
> ===
>
> with a high danger of a mistake leading to inconsistence of these two hierarchies. Not speaking of the factory pattern to replace those pesky static methods, which would, alas, add a third hierarchy for factories; if I wanted to use interface/implementations for factories too, I get _four_ parallel hierarchies, which need to keep consistent! Quadruple ick.
>
> Is there some trick in Groovy which makes this task groovier (or at the very least reasonably manageable), or am I up to my own source preprocessor and/or ASTTs (which again would clash with traits :/ )?

I guess it is up to you. I know of nothing in that area to make this 
less painful

bye Jochen



Re: static propertyMissing in an interface

Posted by OC <oc...@ocs.cz>.
Jochen,

On 3. 4. 2016, at 22:29, Jochen Theodorou <bl...@gmx.org> wrote:

> On 03.04.2016 17:33, OC wrote:
> [...]
>> ===
>> 6 /tmp> <q.groovy
>> class q {
>>  static main(av) {
>>    ExpandoMetaClass.enableGlobally()
>>    Root.metaClass.static.propertyMissing={ name ->
>>      String getter="get${name.capitalize()}"
>>      def body={-> "<$name in $delegate>" }
>>      delegate.metaClass.static."$getter"=body
>>      body.call() // same problem with body(); delegate."$getter"() would work though
>>    }
>>    println "- ${Root.weird}"
>>  }
>> }
>> interface Root {}
>> 7 /tmp> groovy q.groovy
>> Caught: groovy.lang.MissingMethodException: No signature of method: java.io.StringWriter.capitalize() is applicable for argument types: () values: []
>> groovy.lang.MissingMethodException: No signature of method: java.io.StringWriter.capitalize() is applicable for argument types: () values: []
>> 	at q$_main_closure1.doCall(q.groovy:5)
>> 	at q.main(q.groovy:10)
>> 8 /tmp>
> 
> so I misunderstood... it was not, that somehow body was not recognized as closure or such, it is that the execution of  code inside fails. capitalize() is a method on CharSequence, StringWriter is no CharSequence, so the call fails. Did you add such a method yourself? if not, you need to convert to String first.

Convert what?

I call the capitalize method only once, on the name argument of the propertyMissing closure. That is/should be always a String, should it not? Or is there a valid case where this argument would be something else?

Besides the problem disappears if the "body()" or "body.call()" call gets replaced by "delegate."$getter"()", which is sort of weird, for delegate."$getter" actually contains the very body closure :-O

It looks like the way the body closure captures the name variable is... weird: it seems when body.call() is performed, the propertyMissing closure gets called again, this time with a StringWriter for "name", in a way which is completely obscure to me:

===
14 /tmp> <q.groovy      
class q {
 static main(av) {
   ExpandoMetaClass.enableGlobally()
   Root.metaClass.static.propertyMissing={ String name ->
     def body={-> "<$name in $delegate>" }
     body.call()
   }
   println "- ${Root.weird}"
 }
}
interface Root {}
15 /tmp> groovy q.groovy
Caught: groovy.lang.MissingMethodException: No signature of method: q$_main_closure1.doCall() is applicable for argument types: (java.io.StringWriter) values: [- <weird in ]
...
16 /tmp> 
===

Thank you very much and all the best,
OC


Re: static propertyMissing in an interface

Posted by Jochen Theodorou <bl...@gmx.org>.
On 03.04.2016 17:33, OC wrote:
[...]
> ===
> 6 /tmp> <q.groovy
> class q {
>   static main(av) {
>     ExpandoMetaClass.enableGlobally()
>     Root.metaClass.static.propertyMissing={ name ->
>       String getter="get${name.capitalize()}"
>       def body={-> "<$name in $delegate>" }
>       delegate.metaClass.static."$getter"=body
>       body.call() // same problem with body(); delegate."$getter"() would work though
>     }
>     println "- ${Root.weird}"
>   }
> }
> interface Root {}
> 7 /tmp> groovy q.groovy
> Caught: groovy.lang.MissingMethodException: No signature of method: java.io.StringWriter.capitalize() is applicable for argument types: () values: []
> groovy.lang.MissingMethodException: No signature of method: java.io.StringWriter.capitalize() is applicable for argument types: () values: []
> 	at q$_main_closure1.doCall(q.groovy:5)
> 	at q.main(q.groovy:10)
> 8 /tmp>

so I misunderstood... it was not, that somehow body was not recognized 
as closure or such, it is that the execution of  code inside fails. 
capitalize() is a method on CharSequence, StringWriter is no 
CharSequence, so the call fails. Did you add such a method yourself? if 
not, you need to convert to String first.

bye Jochen


Re: static propertyMissing in an interface

Posted by OC <oc...@ocs.cz>.
Jochen,

On 3. 4. 2016, at 7:23, Jochen Theodorou <bl...@gmx.org> wrote:

> On 01.04.2016 03:48, OC wrote:
>> playing with possibilities of the i/i pattern, I have found one can install a static property to an interface, and then use the property all right -- see a proof-of-concept below.
>> 
>> Since it might be used e.g. to create instances or to get a factory through public API based on interfaces (which would otherwise not be possible without exposing the implementation class), this is truly interesting.
>> 
>> The question is: can I rely on this rather arcane behaviour, that it will not be broken in future Groovy versions?
> 
> if you want to be really sure it will continue working it is best if you contribute a test case ;) But I see no plans to change that, especially with java8 being able to define static methods and thus static properties.

Thanks a lot!

> [...]
>>       def body={-> "<$name in $delegate>" }
>>       delegate.metaClass.static."$getter"=body
>>       delegate."$getter"() // I wonder why just "body()" does not work?!?
> 
> no idea why not... but you can always try body.call() instead.

Same as with body():

===
6 /tmp> <q.groovy 
class q {
 static main(av) {
   ExpandoMetaClass.enableGlobally()
   Root.metaClass.static.propertyMissing={ name ->
     String getter="get${name.capitalize()}"
     def body={-> "<$name in $delegate>" }
     delegate.metaClass.static."$getter"=body
     body.call() // same problem with body(); delegate."$getter"() would work though
   }
   println "- ${Root.weird}"
 }
}
interface Root {}
7 /tmp> groovy q.groovy
Caught: groovy.lang.MissingMethodException: No signature of method: java.io.StringWriter.capitalize() is applicable for argument types: () values: []
groovy.lang.MissingMethodException: No signature of method: java.io.StringWriter.capitalize() is applicable for argument types: () values: []
	at q$_main_closure1.doCall(q.groovy:5)
	at q.main(q.groovy:10)
8 /tmp> 
===

Thanks again and all the best,
OC


Re: static propertyMissing in an interface

Posted by Jochen Theodorou <bl...@gmx.org>.
On 01.04.2016 03:48, OC wrote:
> Hello there,
>
> playing with possibilities of the i/i pattern, I have found one can install a static property to an interface, and then use the property all right -- see a proof-of-concept below.
>
> Since it might be used e.g. to create instances or to get a factory through public API based on interfaces (which would otherwise not be possible without exposing the implementation class), this is truly interesting.
>
> The question is: can I rely on this rather arcane behaviour, that it will not be broken in future Groovy versions?

if you want to be really sure it will continue working it is best if you 
contribute a test case ;) But I see no plans to change that, especially 
with java8 being able to define static methods and thus static properties.

[...]
>        def body={-> "<$name in $delegate>" }
>        delegate.metaClass.static."$getter"=body
>        delegate."$getter"() // I wonder why just "body()" does not work?!?

no idea why not... but you can always try body.call() instead.

bye Jochen

static propertyMissing in an interface (was: interface/implementation patten)

Posted by OC <oc...@ocs.cz>.
Hello there,

playing with possibilities of the i/i pattern, I have found one can install a static property to an interface, and then use the property all right -- see a proof-of-concept below.

Since it might be used e.g. to create instances or to get a factory through public API based on interfaces (which would otherwise not be possible without exposing the implementation class), this is truly interesting.

The question is: can I rely on this rather arcane behaviour, that it will not be broken in future Groovy versions?

Thanks,
OC

===
78 /tmp> <q.groovy
class q {
  static main(av) {
    ExpandoMetaClass.enableGlobally()
    Root.metaClass.static.propertyMissing={ name ->
      String getter="get${name.capitalize()}"
      println "... PMISS($name) in $delegate, installing $getter()"
      def body={-> "<$name in $delegate>" }
      delegate.metaClass.static."$getter"=body
      delegate."$getter"() // I wonder why just "body()" does not work?!?
    }

    println "- ${Foo.staticPropertyOfInterfaceWow}"
    println "- ${Bar.itReallyWorks}"
    println "second time, they go directly without PMISS"
    println "- ${Foo.staticPropertyOfInterfaceWow}"
    println "- ${Bar.itReallyWorks}"
  }
}

interface Root {}
interface Foo extends Root {
}
interface Bar extends Foo {
}
79 /tmp> groovy q 
... PMISS(staticPropertyOfInterfaceWow) in interface Foo, installing getStaticPropertyOfInterfaceWow()
- <staticPropertyOfInterfaceWow in interface Foo>
... PMISS(itReallyWorks) in interface Bar, installing getItReallyWorks()
- <itReallyWorks in interface Bar>
second time, they go directly without PMISS
- <staticPropertyOfInterfaceWow in interface Foo>
- <itReallyWorks in interface Bar>
80 /tmp> 
===

Re: interface/implementation patten

Posted by OC <oc...@ocs.cz>.
Jochen,

On 30. 3. 2016, at 20:48, Jochen Theodorou <bl...@gmx.org> wrote:

> I am unhappy about the semantics of static methods in general in Java and that we copied most of it in Groovy...

You are telling me :) Hardly you can have missed my occassional bitter rants re static „methods“ :)

I sort of recall we debated ages ago whether there might be a way to turn them to real full-fledged class methods, properly inheritable with a real “this“ representing the receiver, not the implementor; but I am afraid the result of that conversation was that something like that would be somewhere at the edge betwixt “impossible” and “impractically difficult” :(

> extending that to interface is for me no good decision... but well...

I would be infinitely happier if those jokers in Sun have designed the thing properly (it's not just static “methods“, it's much more -- including the “Cannot cast object” exception howler of the other thread); but well, they did not, triple alas.

Anyway, far as static „methods“, with all their shortcomings, can be part of the class API, I am afraid the interface needs to be able to contain the things. After all, that's the purpose of the interface: to define the public API of the class; no less, no more. If the public API can contain those uglies, the interface should, too.

Or am I overlooking something of importance here?

> I guess it is up to you. I know of nothing in that area to make this less painful

OK, thanks; I guess I'll try to rig some kind of private preprocessor reading sources which would contain ObjC-like class directives, and generating the appropriate .groovy files with all the interfaces, implementations, factories etc. After all, ages ago the C preprocessor used to be implemented this very way, and it worked well.

It would complicate somewhat the incremental build on one side, and error reporting (more precisely, matching the reports to sources) on the other; but the problems should not be insurmountable, I guess -- I need to postprocess error reports anyway, since I use Xcode instead of Eclipse, and thus I have to squeeze the reports so that Xcode understands them. And the big advantage (against the ASTT approach) would be no problem with traits :)

Thanks again a very big lot and all the best,
OC