groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <blackd...@gmx.org>
Subject Re: A @CompileStatic bug, or is it just me: [].withDefault { 0 }
Date Wed, 30 Sep 2015 06:05:25 GMT
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 <soeren@glasius.dk
> <mailto:soeren@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.srkoc@gmail.com
>     <mailto:dinko.srkoc@gmail.com>> wrote:
>
>         On 29 September 2015 at 10:12, Cédric Champeau
>         <cedric.champeau@gmail.com <mailto:cedric.champeau@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.srkoc@gmail.com
>         <mailto:dinko.srkoc@gmail.com>>:
>          >>
>          >> On 29 September 2015 at 09:58, Cédric Champeau
>          >> <cedric.champeau@gmail.com
>         <mailto:cedric.champeau@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
>         <soeren@glasius.dk <mailto:soeren@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/


Mime
View raw message