@CompileStatic void method returns null ?

classic Classic list List threaded Threaded
8 messages Options
MG
Reply | Threaded
Open this post in threaded view
|

@CompileStatic void method returns null ?

MG
Since I just stumbled across this behavior while helping a junior developer debug his code: Why does statically compiled Groovy (2.5.2) return null from void methods, instead of raising a compile error ? 

E.g. 

import groovy.transform.CompileStatic

@CompileStatic

class 
Goo {
void calcId(String a, String b) { // Programming error: Return type should be String
 
"${a}.${b}"
}

String getId() {
 calcId(
"abera","kadavera")
}

String getId2() {
 String id = calcId(
"abera","kadavera")
 
return id
}
}

final 
Goo goo = new Goo()
println 
"goo.calcId(...)=${goo.calcId("x","y")}"
println 
"goo.id=${goo.id}"
println 
"goo.id2=${goo.id2}" 


outputs 


goo.calcId(...)=null 
goo.id=null 
goo.id2=null

Cheers,
mg


Reply | Threaded
Open this post in threaded view
|

Re: @CompileStatic void method returns null ?

Jochen Theodorou
On 28.08.2018 19:45, mg wrote:
> Since I just stumbled across this behavior while helping a junior
> developer debug his code: Why does statically compiled Groovy (2.5.2)
> return null from void methods, instead of raising a compile error ?

i was actually not aware we kept this logic for static compilation, but
essentially it is like that because of dynamic Groovy, which derives
this from the reflective and methodhandles based method invocation

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

Re: @CompileStatic void method returns null ?

paulk_asert
See also: https://issues.apache.org/jira/browse/GROOVY-8770

Which I presume was also to mimick dynamic behavior.

Cheers, Paul.


On Wed, Aug 29, 2018 at 4:42 AM Jochen Theodorou <[hidden email]> wrote:
On 28.08.2018 19:45, mg wrote:
> Since I just stumbled across this behavior while helping a junior
> developer debug his code: Why does statically compiled Groovy (2.5.2)
> return null from void methods, instead of raising a compile error ?

i was actually not aware we kept this logic for static compilation, but
essentially it is like that because of dynamic Groovy, which derives
this from the reflective and methodhandles based method invocation

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

Re: @CompileStatic void method returns null ?

MG
But in what scenario does the dynamic behavior make sense ? You tell the compiler that a method does not have a return value - then you call that method using its return value, knowing it will always be null... ?-)

So the following:

final result = voidMethod() // looks like result might contain something interesting after the call... ?-)

is 100% equivalent to:

voidMethod()
final result = null // ...oooor - not :-/


I feel at least in the @CompileStatic case using a void return value should fail at compile time - what do you think ?


-------- Ursprüngliche Nachricht --------
Von: Paul King <[hidden email]>
Datum: 29.08.18 10:35 (GMT+01:00)
Betreff: Re: @CompileStatic void method returns null ?

See also: https://issues.apache.org/jira/browse/GROOVY-8770

Which I presume was also to mimick dynamic behavior.

Cheers, Paul.


On Wed, Aug 29, 2018 at 4:42 AM Jochen Theodorou <[hidden email]> wrote:
On 28.08.2018 19:45, mg wrote:
> Since I just stumbled across this behavior while helping a junior
> developer debug his code: Why does statically compiled Groovy (2.5.2)
> return null from void methods, instead of raising a compile error ?

i was actually not aware we kept this logic for static compilation, but
essentially it is like that because of dynamic Groovy, which derives
this from the reflective and methodhandles based method invocation

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

Re: @CompileStatic void method returns null ?

Jochen Theodorou
In reply to this post by MG
On 03.09.2018 17:13, mg wrote:
> But in what scenario does the dynamic behavior make sense ?

for a static compiler? none other than being compatible

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

Re: @CompileStatic void method returns null ?

MG
What I meant was: What sense does letting void methods be called make
for the dynamic case, i.e. the dynamic compiler ? From a programmer's
perspective, i.e. what is a programming use case for that
feature/behavior, in dynamic Groovy ?

Of course I can do the following in dynamic Groovy:

// Groovy 2.5.0
class Goo {
     //void nogoo() { return 123 } // Dynamic Groovy compiler: RuntimeParserException: Cannot use return statement with an expression on a method that returns void
     void nogoo() { 123 }
}

final goo = new Goo()

println "original: goo.nogoo()=${goo.nogoo()}"

goo.metaClass.nogoo = { return 456 }

println "mopped: goo.nogoo()=${goo.nogoo()}"


Which will build, run, and output

original: goo.nogoo()=null
mopped: goo.nogoo()=456

  i.e. returning 456 from a void method in the second case.
But if I am using a library that includes the Goo class, why would I
ever expect a return value from the nogoo method (and therefore call
it), considering its return type is void ? And if I control the Goo
class myself, why would I not just change its return type to int or def ?

Cheers,
mg


On 03.09.2018 22:36, Jochen Theodorou wrote:
> On 03.09.2018 17:13, mg wrote:
>> But in what scenario does the dynamic behavior make sense ?
>
> for a static compiler? none other than being compatible
>
> bye Jochen
>

Reply | Threaded
Open this post in threaded view
|

Re: @CompileStatic void method returns null ?

paulk_asert
Calling void methods is fine. Expecting a result is the point in question.

For dynamic Groovy, you can't always tell which case you have:

class Foo {
  def bar() { 42 }
  void baz() { }
}

def method(boolean condition, delegate, meth1, meth2) {
  if (condition) delegate."$meth1"()
  else delegate."$meth2"()
}

println method(true, new Foo(), 'bar', 'baz') // 42
println method(false, new Foo(), 'bar', 'baz') // null

Here, "method" is expecting to return some value that happens to be the last expression, i.e. the result of the if/then/else expression, so we return null in such cases.

Cheers, Paul.


On Tue, Sep 4, 2018 at 7:38 AM MG <[hidden email]> wrote:
What I meant was: What sense does letting void methods be called make
for the dynamic case, i.e. the dynamic compiler ? From a programmer's
perspective, i.e. what is a programming use case for that
feature/behavior, in dynamic Groovy ?

Of course I can do the following in dynamic Groovy:

// Groovy 2.5.0
class Goo {
     //void nogoo() { return 123 } // Dynamic Groovy compiler: RuntimeParserException: Cannot use return statement with an expression on a method that returns void
     void nogoo() { 123 }
}

final goo = new Goo()

println "original: goo.nogoo()=${goo.nogoo()}"

goo.metaClass.nogoo = { return 456 }

println "mopped: goo.nogoo()=${goo.nogoo()}"


Which will build, run, and output

original: goo.nogoo()=null
mopped: goo.nogoo()=456

  i.e. returning 456 from a void method in the second case.
But if I am using a library that includes the Goo class, why would I
ever expect a return value from the nogoo method (and therefore call
it), considering its return type is void ? And if I control the Goo
class myself, why would I not just change its return type to int or def ?

Cheers,
mg


On 03.09.2018 22:36, Jochen Theodorou wrote:
> On 03.09.2018 17:13, mg wrote:
>> But in what scenario does the dynamic behavior make sense ?
>
> for a static compiler? none other than being compatible
>
> bye Jochen
>

MG
Reply | Threaded
Open this post in threaded view
|

Re: @CompileStatic void method returns null ?

MG
But the call to Foo#baz() coud return an e.g. GroovyVoidObject instance, which in turn throws a "cannot return void from method" if that happens to be the last expression in your example, no ?
It feels like returning null here is just a stopgap, not anything one actually wants to have in the language...

I don't expect the dynamic compiler to be changed, but should we really mirror the dynamic comiler behavior in the static compiler in this case ? I think it would be much more least surprise in the @CompileStatic case...

Cheers,
mg

PS: Calling void methods better be fine, otherwise why do they exist in the first place ;-)  - I am/was always referring to my initial question, so the whole thread is about expecting/using void method call results somewhere...


On 04.09.2018 01:41, Paul King wrote:
Calling void methods is fine. Expecting a result is the point in question.

For dynamic Groovy, you can't always tell which case you have:

class Foo {
  def bar() { 42 }
  void baz() { }
}

def method(boolean condition, delegate, meth1, meth2) {
  if (condition) delegate."$meth1"()
  else delegate."$meth2"()
}

println method(true, new Foo(), 'bar', 'baz') // 42
println method(false, new Foo(), 'bar', 'baz') // null

Here, "method" is expecting to return some value that happens to be the last expression, i.e. the result of the if/then/else expression, so we return null in such cases.

Cheers, Paul.


On Tue, Sep 4, 2018 at 7:38 AM MG <[hidden email]> wrote:
What I meant was: What sense does letting void methods be called make
for the dynamic case, i.e. the dynamic compiler ? From a programmer's
perspective, i.e. what is a programming use case for that
feature/behavior, in dynamic Groovy ?

Of course I can do the following in dynamic Groovy:

// Groovy 2.5.0
class Goo {
     //void nogoo() { return 123 } // Dynamic Groovy compiler: RuntimeParserException: Cannot use return statement with an expression on a method that returns void
     void nogoo() { 123 }
}

final goo = new Goo()

println "original: goo.nogoo()=${goo.nogoo()}"

goo.metaClass.nogoo = { return 456 }

println "mopped: goo.nogoo()=${goo.nogoo()}"


Which will build, run, and output

original: goo.nogoo()=null
mopped: goo.nogoo()=456

  i.e. returning 456 from a void method in the second case.
But if I am using a library that includes the Goo class, why would I
ever expect a return value from the nogoo method (and therefore call
it), considering its return type is void ? And if I control the Goo
class myself, why would I not just change its return type to int or def ?

Cheers,
mg


On 03.09.2018 22:36, Jochen Theodorou wrote:
> On 03.09.2018 17:13, mg wrote:
>> But in what scenario does the dynamic behavior make sense ?
>
> for a static compiler? none other than being compatible
>
> bye Jochen
>