groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Paul King <>
Subject Fwd: About supporting `var` of Java10+
Date Sat, 10 Mar 2018 02:51:29 GMT
Hi, sorry I meant to respond to the list too. Messages included below.

---------- Forwarded message ----------
From: MG <>
Date: Sat, Mar 10, 2018 at 7:19 AM
Subject: Re: About supporting `var` of Java10+

Hi Paul,

did you reply to just me on purpose ?

On 09.03.2018 03:11, Paul King wrote:

I am mostly worried about non-denotable types. Perhaps we could see how far
we can get just applying the same rules that Java will:

I feel like all the non-denotable types are pretty rare edge cases in
practice, so maybe using var === def for them would be ok... ?

Having said that, the non-denotable types they list are:

# A null-typed variable is practically useless, and there is no good
alternative for an inferred type, so we reject these.

I agree => error if assigned value is null.

# Allowing capture variables to flow into subsequent statements adds new
expressiveness to the language, but that's not a goal of this feature.
Instead, the proposed projection operation is one we need to use anyway to
address various bugs in the type system (see, e.g., JDK-8016196), and it's
reasonable to apply it here.

I am not sure how this maps to Groovy...

# Intersection types are especially difficult to map to a supertype—they're
not ordered, so one element of the intersection is not inherently "better"
than the others. The stable choice for a supertype is the lub of all the
elements, but that will often be Object or something equally unhelpful. So
we allow them.

I have never used intersection types. I would really be interested to know
how many people have ever used them.
I tried the following in Groovy, but got a

Error:(32, 17) Groovyc: [Static type checking] - No such property: s for
class: T

compile time error (even though IntelliJ did not complain about the

@CompileStaticclass GroovyIntersectionTypesSpike {
  static interface Intf0 { Number getX() }
  static interface Intf1 { String getS() }

  @Canonical static class Foo implements Intf0, Intf1 {
    Number x; String s  }

  @Test  void intersectionTypesTest() {
    print(new Foo(123,'abc'))

  public <T extends Intf0 & Intf1> void print(final T t) {
    println "x=$t.x"    println "s=$t.s"  }

# Anonymous class types cannot be named, but they're easily
understood—they're just classes. Allowing variables to have anonymous class
types introduces a useful shorthand for declaring a singleton instance of a
local class. We allow them.

How do you assign a new value to a variable that has a type that exists
only once:

@CompileStaticclass GroovyAnonymousTypesSpike {
  @Canonical static class Foo { String s }

  @Test  void anonymousTypesTest() {
    Foo x0a = new Foo("x0a") {}
    Foo x0b = new Foo("x0b") {}
    printFoos(x0a, x0b)

    Foo x1a = createAnonymousFooChild("x1a")
    Foo x1b = createAnonymousFooChild("x1b")
    printFoos(x1a, x1b)

  Foo createAnonymousFooChild(String s ) {
    return new Foo(s) {}

  void printFoos(Foo f0, Foo f1) {
    println "\nprintFoos:"    printFoo(f0)
    println "are foos playing ball: ${}"  }
  void printFoo(Foo f) {
    println "${f.getClass().name} (${f.getClass().canonicalName}): s=$f.s"  }

  @Test  void intersectionTypesTest2() {
    def afc0 = new Foo() { String speak() { return "Foo Child0: I am
${getClass().name} (${getClass().canonicalName})" } }
    def afc1 = new Foo() { String speak() { return "Foo Child1: I am
${getClass().name} (${getClass().canonicalName})" } }
    println afc0.speak()
    println afc1.speak()

groovy.GroovyAnonymousTypesSpike$1 (null): s=x0a
groovy.GroovyAnonymousTypesSpike$2 (null): s=x0b
are foos playing ball: false

groovy.GroovyAnonymousTypesSpike$3 (null): s=x1a
groovy.GroovyAnonymousTypesSpike$3 (null): s=x1b
are foos playing ball: false

Maybe I am overlooking something, but using the anonymous type here looks
like it would effectively make the variable final. So it looks like using
the non-anonymous super class might make more sense here (it would not
break Java compatibility, and would give programmers more options, if final
is also changed in Groovy to use the RHS type instead of Object).

So some of the simple immediate implications are:
* error if var used for fields

As I said supporting that would feel Groovy to me, so if it is easy to do I
would support it, but I don't see it as essential in any way.

* error if var used with no initializer statement

Agreed. Or if null type is assigned.

* we'll need some kind of marker in the AST for var (as Jochen already
mentioned I think)

Yes, Jochen did say that.

The devil will be in the detail when we try to update the type checker

I assume the replacement
var x = RHS
typeof(RHS) x = RHS
cannot be done before the type checker runs ?

- and for dynamic Groovy I suspect we might need some additional
restrictions in addition to those chosen by Java.

Stupid question: Why ?-)
Isn't the dynamic case just
1) var -> typeof(RHS)
2) done

I hope we can make this happen...

View raw message