This actually highlights a general problem with static compilation and extension methods.

Extension methods are not part of the class in the Java sense. Thus there is no virtual method call. This means that if the compiler assumes the wrong type, it will call the wrong method. In Java everything is fine as long as the "wrongly" assumed type is a super type and defines the method. Example:

class Foo {
  int foo(){1}
}
class Bar extends Foo {
  int foo(){2}
}
def method(Foo f) {
  return f.foo()
}
assert method(new Foo()) == 1
assert method(new Bar()) == 2

A static compiler will select Foo#foo() for the call, but since the method call is done virtual, you still end up doing Bar#foo() if f is Bar. But with extension methods:

class Foo{}
class ExtensionMethodsForFoo { // placed so compiler knows this
  static int foo(Foo f){1}
}
class Bar extends Foo{
  int foo(){2}
}
assert method(new Foo()) == 1
assert method(new Bar()) == 1

Again the compiler will only see Foo#foo, because he cannot know better. But since the call cannot be virtual, there is no way of calling Bar#foo this way. It would also be the same if Bar#foo is defined as extension method as well.

In general: inheritance with extension methods does not work properly for static compiled Groovy. It cannot imho.

For the case here, it might be a workaround to let the withDefault method not return List (which will let the compiler then later select List#getAt from DGM), but to use the specific type (ListWithDefault or something). Then the compiler can select the proper method through flow typing. Of course, as soon as you moves parts of the code in another method, you may end up with the same problem. So it is not a really refactoring-safe solution. But better than nothing I guess.

Anyway... just wanted to confirm you guys why this is no static compilation bug.

Of course you could think about doing double dispatch in the DGM method, but either you do dynamic calls from there and loose the advantage of static compilation, or

bye blackdrag

Am 29.09.2015 23:58, schrieb Shil Sinha:
The bytecode for x[n] is:

  ILOAD 1
     INVOKESTATIC org/codehaus/groovy/runtime/DefaultGroovyMethods.getAt
(Ljava/util/List;I)Ljava/lang/Object;

The implementation of DGM.getAt(List, int) returns null if the given
index is >= the size of the list, so this makes sense. Seems like a bug
in the DGM implementation more than @CompileStatic.

On Tue, Sep 29, 2015 at 5:17 PM, Søren Berg Glasius <soe...@glasius.dk
<mailto:soe...@glasius.dk>> wrote:

    Should I file a bug report?


    Best regards / Med venlig hilsen,
    Søren Berg Glasius

    Hedevej 1, Gl. Rye, 8680 Ry, Denmark
    Mobile: +45 40 44 91 88 <tel:%2B45%2040%2044%2091%2088>, Skype:
    sbglasius
    --- Press ESC once to quit - twice to save the changes.

    On 29 September 2015 at 10:17, Dinko Srkoč <dinko.sr...@gmail.com
    <mailto:dinko.sr...@gmail.com>> wrote:

        On 29 September 2015 at 10:12, Cédric Champeau
        <cedric.champ...@gmail.com <mailto:cedric.champ...@gmail.com>>
        wrote:
        > That's because it's withDefault { 1 } ;)

        Argh! Still morning for me. :-(

         >
         > 2015-09-29 10:05 GMT+02:00 Dinko Srkoč <dinko.sr...@gmail.com
        <mailto:dinko.sr...@gmail.com>>:
         >>
         >> On 29 September 2015 at 09:58, Cédric Champeau
         >> <cedric.champ...@gmail.com
        <mailto:cedric.champ...@gmail.com>> wrote:
         >> > This looks like a bug. Would be interesting to look at the
        bytecode to
         >> > check
         >> > what method is called for x[n].
         >>
         >> Curiously, I tried to do just that in the Groovy AST Browser
        and, for
         >> the following piece of code:
         >>
         >>   @groovy.transform.CompileStatic
         >>   def foo() {
         >>       [].withDefault(1)
         >>   }
         >>
         >> got this:
         >>
         >> Unable to produce AST for this phase due to earlier
        compilation error:
         >> startup failed:
         >> script1443513793544.groovy: 3: [Static type checking] -
        Cannot find
         >> matching method java.util.List#withDefault(int). Please
        check if the
         >> declared type is right and if the method exists.
         >>  @ line 3, column 5.
         >>        [].withDefault(1)
         >>        ^
         >>
         >> That's Groovy 2.4.4
         >>
         >> Cheers,
         >> Dinko
         >>
         >> >
         >> > 2015-09-29 9:54 GMT+02:00 Søren Berg Glasius
        <soe...@glasius.dk <mailto:soe...@glasius.dk>>:
         >> >>
         >> >> Hi Fellows,
         >> >>
         >> >> I stumbled upon this today.
         >> >>
         >> >> This code runs:
         >> >>
         >> >> class Test {
         >> >>     private List<Integer> x = [].withDefault { 0 }
         >> >>     Integer getValue(int n) {
         >> >>         return x[n]
         >> >>     }
         >> >> }
         >> >> assert new Test().getValue(5) == 0
         >> >>
         >> >> where as when I compile static:
         >> >>
         >> >> @CompileStatic
         >> >> class Test {
         >> >>     private List<Integer> x = [].withDefault { 0 }
         >> >>     Integer getValue(int n) {
         >> >>         return x[n]
         >> >>     }
         >> >> }
         >> >> assert new Test().getValue(5) == 0
         >> >>
         >> >> I get an assertion failed, because new Test().getValue(5)
        == null
         >> >>
         >> >> Is this expected behavior or a bug?
         >> >>
         >> >>
         >> >> Best regards / Med venlig hilsen,
         >> >> Søren Berg Glasius
         >> >>
         >> >> Hedevej 1, Gl. Rye, 8680 Ry, Denmark
         >> >> Mobile: +45 40 44 91 88 <tel:%2B45%2040%2044%2091%2088>,
        Skype: sbglasius
         >> >> --- Press ESC once to quit - twice to save the changes.
         >> >
         >> >
         >
         >





--
Jochen "blackdrag" Theodorou
blog: http://blackdragsview.blogspot.com/

Reply via email to