About supporting `var` of Java10+

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
33 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

Re: About supporting `var` of Java10+

paulk_asert


On Fri, Mar 9, 2018 at 5:46 AM, Aarjav Patel <[hidden email]> wrote:
Hi all,

I do not know all of the intricacies in the difference between current groovy def and the proposed java var. However as a groovy 'user' coming from a Javan background, I would like or expect var in groovy to be treated/behave the same way as in java. def then would be an 'enhanced' version of var which works better (?) with other language features. This way there are less surprises when using var.
 
But Java doesn't have a dynamic mode so it is difficult to offer the exact same behavior. We could prohibit "var" from being used in dynamic Groovy but users might expect to be able to cut and paste from Java and run in dynamic mode. So, I am suggesting that for dynamic mode that correct code copied and pasted will run as expected and incorrect code will fail "as expected" but at runtime. With the caveat being that Groovy does have some other differences to Java which would come into play. This is how "def" behaves now. Similarly, for static Groovy, I am suggesting "def" behavior. This is slightly different to Java's behavior - the Groovy type checker employ's flow typing which is a different approach to Java's but similar in many situations. My suspicion is that if we write a second chunk of the type checker with Java only semantics for "var", then in code with mixed "var" and "def" definitions, it will become more difficult for programmers to follow what is going on.

Unfortunately I have not looked at 2.5+ regarding lambdas. Are they just another way to denote a closure? Just wondering how it was handled so that maybe it can give us similar options for var/def.

The special lambda support is a 2.6/3 feature. It would be great to discuss that further but it's not the topic here. In 2.5 there is no change to the existing "lambda" support which essentially boils down to coercion of Closures to SAM interfaces including all of those that underpin Java's lambdas.
 
Thanks,

- Aarjav

On Mar 8, 2018 8:58 AM, "mg" <[hidden email]> wrote:
My argument was not in relation to the JEP, but a Groovy user story, in relation to you saying, that I would not see a difference between def and var, apart from when assigning a value later on. 

But assigning a value later on is _exactly_ what I am going to do when I use var - because otherwise I would use final instead of var...

-------- Ursprüngliche Nachricht --------
Von: Jochen Theodorou <[hidden email]>
Datum: 08.03.18 13:32 (GMT+01:00)
Betreff: Re: About supporting `var` of Java10+



Am 08.03.2018 um 12:45 schrieb mg:
> Maybe I am missing your point, but what I meant was: When I use
>
> var x = new Foo()
>
> I indicate that x will be reassigned further down in the scope,
> otherwise I use
>
> final x = new Foo()

That's what I understood. But the later variant is not part of the JEP.
In Groovy what you wrote is an alias for final Object x = new Foo()

bye Jochen

MG
Reply | Threaded
Open this post in threaded view
|

Re: About supporting `var` of Java10+

MG
In reply to this post by paulk_asert
Hi Paul,
  1. If I will assign a value to a variable later, I would use var with Java semantics. Without var I give the type of the variable explicitely as restrictive as possible. I would not use def (I only use def as the return value for a method returning an anonymous class instance, since IntelliJ Intellisense picks up the type in that case, contrary to when using Object as the return type).
  2. If I will not assign a value to a variable later on, I use final.
(Jochen's argument, as I understood it, was, that my idea of var (close to what Java will do) differs from Groovy's def only when assigning a value to the variable later on. To which I replied that in my book that is in 100% of all cases (because otherwise I use final)).

In code:

@Canonical static class FoorchterlichLongerNome { Number x; String s }

@Test
void finalFooVarTest() {
  final x = new FoorchterlichLongerNome(123,'abc')
  println "x=$x"
  x = 987
  println "x=$x"
}

Compile time error:
Error:(23, 5) Groovyc: The variable [x] is declared final but is reassigned


@Test
void fooVarTest() {
  FoorchterlichLongerNome x = new FoorchterlichLongerNome(123,'abc')
  //var x = new FoorchterlichLongerNome(123,'abc') // equivalent to the above line in var with Java semantics
  println "x=$x"
  x = new FoorchterlichLongerNome(4567,'DEFG')
  println "x=$x"
  x = 987
  println "x=$x"
}

Runtime error:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '987' with class 'java.lang.Integer' to class 'groovy.Groovy_var_keyword_Spike$FoorchterlichLongerNome'

@Test
void defFooVarTest() {
  def x = new FoorchterlichLongerNome(123,'abc')
  //var x = new FoorchterlichLongerNome(123,'abc') // equivalent to the above line in var with Groovy def semantics
  println "x=$x"
  x = 987
  println "x=$x"
}

Output:
x=groovy.Groovy_var_keyword_Spike$FoorchterlichLongerNome(123, abc)
x=987



On 08.03.2018 23:42, Paul King wrote:
So in that one aspect of "assigning a value later on" your expectation is exactly like Java's "var" and Groovy's current "def"?


On Thu, Mar 8, 2018 at 11:58 PM, mg <[hidden email]> wrote:
My argument was not in relation to the JEP, but a Groovy user story, in relation to you saying, that I would not see a difference between def and var, apart from when assigning a value later on. 

But assigning a value later on is _exactly_ what I am going to do when I use var - because otherwise I would use final instead of var...

-------- Ursprüngliche Nachricht --------
Von: Jochen Theodorou <[hidden email]>
Datum: 08.03.18 13:32 (GMT+01:00)
Betreff: Re: About supporting `var` of Java10+



Am 08.03.2018 um 12:45 schrieb mg:
> Maybe I am missing your point, but what I meant was: When I use
>
> var x = new Foo()
>
> I indicate that x will be reassigned further down in the scope,
> otherwise I use
>
> final x = new Foo()

That's what I understood. But the later variant is not part of the JEP.
In Groovy what you wrote is an alias for final Object x = new Foo()

bye Jochen


MG
Reply | Threaded
Open this post in threaded view
|

Re: About supporting `var` of Java10+

MG
In reply to this post by paulk_asert


On 08.03.2018 14:13, Paul King wrote:

On Thu, Mar 8, 2018 at 9:53 PM, mg <[hidden email]> wrote:

I would be interested to hear if you see some advantages of going down the
#define var def
route - apart from the obvious, that it is the easiest/fastest to implement ?

I am not too worried about ease/speed of implementation but I think we have to be on a continual quest for simplification.
So for "def"/"var" if we just decide things organically as we go we might end up with numerous differences:

<zip>


and so forth.
And then that complexity travels throughout the code base multiplying against the other orthogonal axes where differences occur.
Before we know it we can end up with an explosion of complexity that has to be maintained.

I see that argument in general, but here it seems to be mostly that "var" is allowed in more places than "def" - would that really lead to an explosion of complexity ?
Also would those differences not also exist in the var === def case ?

But also, if we want to make Groovy Java "var" friendly, what simple explanation can we give
knowing that Groovy is a different language to Java?
For dynamic Groovy, it can't really mean much different to "def" (effectively Object).

Not true, shown by the examples in my last mail, which is completely dynamic Groovy: Assignment fails during runtime in var-equivalent-case, and works in def-case.

Java is introducing "var" it to reduce ceremony for local variables, i.e. maximise type inferencing.
However, that is what we already do (albeit backed by a flow typing semantics different to Java)

The flow typing cannot deduce what is not expressed, in this case the type we want a variable to be restricted to. So var and flow typing are orthogonal concepts.

The argument on the flip side is fairly simple too. We have two names, we can use those to
represent two different concepts.

One of them being exactly the concept Java uses, the other a much more lenient concept coming from the dynamic part of the Groovy world.

Even Java considered different names:
let, val, auto, const, or final, instead of or in conjunction with var. But given what they have
decided - a semantics very close to our "def"

Yes, def can be used to fake var, but it is not var.
By the same argument you could ask, why Groovy supports much more complex (to implement and maintain) concepts such @CompileStatic and flow typing, when everything works exactly the same as in the dynamic case (i.e. dynamic Groovy code looks like static Groovy code or Java - but the underlying semantics are different).

In the end it boils down to: var === def would keep Groovy look and feel like Java, while var with Java-like semantics would do that _and_ extend the possibilities of Groovy developers to more easily express themselves. That "more" comes at a price, in current and future development efforts, just as any other language feature...

To me, coming more from a non-def-using, type-safe, easier-to-read-code perspective, I feel like it is a wasted opportunity, now that a var keyword is being introduced, because once var === def has been coosen, changing its semantics to Java-like later on would be a breaking change, and will therefore most likely not happen. So for all the Groovy developers that see Groovy as a fully blown, mostly statically typed language, I would ask you to reconsider :-)

mg






MG
Reply | Threaded
Open this post in threaded view
|

Re: About supporting `var` of Java10+

MG
In reply to this post by paulk_asert


On 09.03.2018 00:01, Paul King wrote:
But Java doesn't have a dynamic mode so it is difficult to offer the exact same behavior. We could prohibit "var" from being used in dynamic Groovy but users might expect to be able to cut and paste from Java and run in dynamic mode.

I am convinced that is what people expect, at least that was exactly what I did, and what I tell Java developers is so great about Groovy: Just start by pasting/writing Java without semicolons at the end of each line, and learn as you go along.
I feel I am missing something here, because where you seem to see problems, in my mind var "just" gets replaced by the RHS type as early as possible - why would this raise any problems in dynamic or static Groovy ?

var x = RHS

becoming

typeof(RHS) x = RHS

gives exactly what any developer who knows var would expect, no ?









Reply | Threaded
Open this post in threaded view
|

Fwd: About supporting `var` of Java10+

paulk_asert

Hi, sorry I meant to respond to the list too. Messages included below.

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


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:
http://openjdk.java.net/jeps/286#Non-denotable-types

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 construct):
@CompileStatic
class 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:
@CompileStatic
class 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)
    printFoo(f1)
    println "are foos playing ball: ${f0.is(f1)}"
  }
  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()
  }
}

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

printFoos:
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
becoming
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...
Markus




Reply | Threaded
Open this post in threaded view
|

Re: Fwd: About supporting `var` of Java10+

Jochen Theodorou
On 10.03.2018 03:51, Paul King wrote:
>
> Hi, sorry I meant to respond to the list too. Messages included below.
>
> ---------- Forwarded message ----------
> From: *MG* <[hidden email] <mailto:[hidden email]>>
> Date: Sat, Mar 10, 2018 at 7:19 AM
> Subject: Re: About supporting `var` of Java10+
> To: [hidden email] <mailto:[hidden email]>
[...]
> # 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

if you have for example this:

def x
if (b) {
   x = y;
} else {
   x = z;
}
x.foo()

then what is the type for x, to check if foo() is an allowed method? The
answer in Groovy is, it is the LUB(type(z),type(y)). The result might be
an intersection type for x, that for example consists of Object and all
interfaces the two have in common.

[...]
> # 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:

In Java with var you don´t

[...]
> 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).

I can do

var x = new Object() {
   public void foo(){}
};
x.foo();

Using Object for x, does no longer allow you to call foo(). The only
variant this can be made work in Java right now is by not using an
anonymous inner class. This here is the "declaring a singleton instance
of a local class" that is intended to be allowed.

>> 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.

In a field declaration like "var x = 1" we can do it. We cannot do it
for the anonymous inner class, if we are supposed to take the specific
class. We cannot do it for intersection like types, because we need a
real type to give to the field. We cannot do it if the initialization is
in more than one place (multiple constructor for example) and probably a
few more. I would definitely go without this first.

[...]
>> The devil will be in the detail when we try to update the type checker
>
> I assume the replacement
> var x = RHS
> becoming
> typeof(RHS) x = RHS
> cannot be done before the type checker runs ?

nope

>> - 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 think for dynamic Groovy we should do var == def. we cannot do var ->
typeof(RHS), because we may not know the RHS type at compile time. And
at runtime the RHS type is really not of that much use anymore.

But for me that means the more restricted one is var in static
compilation, not dynamic.

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

Re: Fwd: About supporting `var` of Java10+

MG
Hi Jochen,

I was not aware that Groovy is so sophisticated in its expression analysis, that it actually uses intersection types - I had assumed it would fall back to Object in these cases :-)
Much of what Groovy does here is of course obscured by Intellisense warnings ;-)
(btw @[hidden email]: Is that parser completely independent, or is it based on Groovy, CodeNarc, etc code ?)


I thought of a possible entirely different rout to take for "var" in the dynamic case, namely that var could be forbidden in dynamic case (based on the fact that it makes little to no sense), throwing a CTE like:
"'var' is not supported in dynamic Groovy code. Annotate the method/class with @CompileStatic to switch to static compilation, or replace 'var' with 'def'."
Rationale:
  1. Var can currently only come from Java code copy & pastedinto Groovy code. This CTE would give a hint to the person doing that, that Groovy has a static compilation mode, and that if he is coming from Java, that is maybe what he actually wants to use, to semantically as close to Java as possible (and not have e.g. stuff like null.forEach {} being valid code).
  2. It does not hinder Groovy in any way, since there is no reason for anyone programming dynamic Groovy to use var instead of def.
  3. It would, on the other hand, allow to introduce var support not based on var === def to dynamic Groovy later on, without breaking backwards compatibility (because  var x = new Foo(); x = 123 suddenly does not work any more)

Just food for thought - I personally would prefer to see the "90% solution" I talked about in an earlier post for dynamic Groovy:
Support var x = RHS -> typeof(RHS) x = RHS for simple cases, such as:
var x = new Foo(...)
var x = (Foo) ...
var x = foo(...) // use the explicit return type of method foo(), CTE on return type == def ("'var' not supported for 'def' as return type - use Object as return type of method or define variable using 'def'.")
throw CTE in all other cases (least surprise - "'Type for variable defined with 'var' cannot be deduced in dynamic Groovy. Annotate the method/class with @CompileStatic to switch to static compilation, or replace 'var' with 'def'."

Maybe I am seeing things too rosy, but I feel that dynamic Groovy should not completely loose out on var.
From the view of my framework code that goes even more so for the related case of final x = RHS -> final typeof(RHS) x = RHS I therefore keep going on about - if dynamic Groovy does not pick up the RHS type for final, I need to keep my current code, or force framework users to use @CompileStatic on all Table derived classes, if they want to define table columns in the most elegant and concise way... :-)
mg




On 10.03.2018 14:23, Jochen Theodorou wrote:
On 10.03.2018 03:51, Paul King wrote:

Hi, sorry I meant to respond to the list too. Messages included below.

---------- Forwarded message ----------
From: *MG* <[hidden email] [hidden email]>
Date: Sat, Mar 10, 2018 at 7:19 AM
Subject: Re: About supporting `var` of Java10+
To: [hidden email] [hidden email]
[...]
# 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

if you have for example this:

def x
if (b) {
  x = y;
} else {
  x = z;
}
x.foo()

then what is the type for x, to check if foo() is an allowed method? The answer in Groovy is, it is the LUB(type(z),type(y)). The result might be an intersection type for x, that for example consists of Object and all interfaces the two have in common.

[...]
# 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:

In Java with var you don´t

[...]
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).

I can do

var x = new Object() {
  public void foo(){}
};
x.foo();

Using Object for x, does no longer allow you to call foo(). The only variant this can be made work in Java right now is by not using an anonymous inner class. This here is the "declaring a singleton instance of a local class" that is intended to be allowed.

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.

In a field declaration like "var x = 1" we can do it. We cannot do it for the anonymous inner class, if we are supposed to take the specific class. We cannot do it for intersection like types, because we need a real type to give to the field. We cannot do it if the initialization is in more than one place (multiple constructor for example) and probably a few more. I would definitely go without this first.

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

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

nope

- 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 think for dynamic Groovy we should do var == def. we cannot do var -> typeof(RHS), because we may not know the RHS type at compile time. And at runtime the RHS type is really not of that much use anymore.

But for me that means the more restricted one is var in static compilation, not dynamic.

bye Jochen


Reply | Threaded
Open this post in threaded view
|

Re: About supporting `var` of Java10+

Daniel.Sun
In reply to this post by Daniel Sun
As a side note,  `var` of Java10+ supports the following usage[1]:

```
var person = new Object() {
   String name = "bob";
   int age = 5;
};
 
System.out.println(person.name + " aged " + person.age);
```

Cheers,
Daniel.Sun

[1]
http://benjiweber.co.uk/blog/2018/03/03/representing-the-impractical-and-impossible-with-jdk-10-var/




--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Daniel Sun
Apache Groovy committer

Blog: http://blog.sunlan.me
Twitter: @daniel_sun
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: About supporting `var` of Java10+

Jochen Theodorou
In reply to this post by MG
On 10.03.2018 20:33, MG wrote:
> Hi Jochen,
>
> I was not aware that Groovy is so sophisticated in its expression
> analysis, that it actually uses intersection types

you actually do not have much of a choice. It is an AST-only
representation only though.

[...]
>  3. It would, on the other hand, allow to introduce var support not
>     based on var === def to dynamic Groovy later on, without breaking
>     backwards compatibility (because  var x = new Foo(); x = 123
>     suddenly does not work any more)

what exactly is the advantage of not having var === def? Only to
disallow the reassignment in some cases at runtime? I do not see much
gain in that actually

> Just food for thought - I personally would prefer to see the "90%
> solution" I talked about in an earlier post for dynamic Groovy:
> Support var x = RHS -> typeof(RHS) x = RHS for simple cases, such as:
> var x = new Foo(...)
> var x = (Foo) ...
> var x = foo(...) // use the explicit return type of method foo(), CTE on
> return type == def ("'var' not supported for 'def' as return type - use
> Object as return type of method or define variable using 'def'.")
> throw CTE in all other cases (least surprise - "'Type for variable
> defined with 'var' cannot be deduced in dynamic Groovy. Annotate the
> method/class with @CompileStatic to switch to static compilation, or
> replace 'var' with 'def'."

there is almost no expressions consisting of multiple expression, that
we can tell the type of in dynamic mode. Even something simple as 1+1
can in theory return a ComplexNumber suddenly.

[...]
>  From the view of my framework code that goes even more so for the
> related case of final x = RHS -> final typeof(RHS) x = RHS I therefore
> keep going on about - if dynamic Groovy does not pick up the RHS type
> for final, I need to keep my current code, or force framework users to
> use @CompileStatic on all Table derived classes, if they want to define
> table columns in the most elegant and concise way... :-)

for "final x = ..." the exact type of x is in dynamic mode actually
totally not relevant. There is no reassignment, so that problem is out
here. But if we forget about that, then there is no difference between
"final x" and "def x". I know cases where it could make a difference,
but they do not exist in Groovy yet. so what exactly is final x supposed
to do different than def x besides the reassignment?

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

Re: Fwd: About supporting `var` of Java10+

MG


On 11.03.2018 14:58, Jochen Theodorou wrote:
> On 10.03.2018 20:33, MG wrote:
>> Hi Jochen,
>>
>> I was not aware that Groovy is so sophisticated in its expression
>> analysis, that it actually uses intersection types
>
> you actually do not have much of a choice. It is an AST-only
> representation only though.

What I meant was: Since Groovy is for instance still using dynamic call
site resolution in @CompileStatic mode (see: Minecraft obfuscation
problem), it might conceivably also fall back to Object & dynamic
resolution in such cases...

> [...]
>>  3. It would, on the other hand, allow to introduce var support not
>>     based on var === def to dynamic Groovy later on, without breaking
>>     backwards compatibility (because  var x = new Foo(); x = 123
>>     suddenly does not work any more)
>
> what exactly is the advantage of not having var === def? Only to
> disallow the reassignment in some cases at runtime? I do not see much
> gain in that actually

Disallow and document for anyone reading the code, yes (always the same
argument).

>
>> Just food for thought - I personally would prefer to see the "90%
>> solution" I talked about in an earlier post for dynamic Groovy:
>> Support var x = RHS -> typeof(RHS) x = RHS for simple cases, such as:
>> var x = new Foo(...)
>> var x = (Foo) ...
>> var x = foo(...) // use the explicit return type of method foo(), CTE
>> on return type == def ("'var' not supported for 'def' as return type
>> - use Object as return type of method or define variable using 'def'.")
>> throw CTE in all other cases (least surprise - "'Type for variable
>> defined with 'var' cannot be deduced in dynamic Groovy. Annotate the
>> method/class with @CompileStatic to switch to static compilation, or
>> replace 'var' with 'def'."
>
> there is almost no expressions consisting of multiple expression, that
> we can tell the type of in dynamic mode. Even something simple as 1+1
> can in theory return a ComplexNumber suddenly.

We already touched on that topic in the past: I still think that allowing
new Foo()
or
Foo myFoo(...)
to return anything that is not of type Foo is "too flexible", and
therefore should be disallowed, or fail.

Afaics Intellisense also operates on the assumption that types given are
honored in dynamic Grooy.

>
> [...]
>>  From the view of my framework code that goes even more so for the
>> related case of final x = RHS -> final typeof(RHS) x = RHS I
>> therefore keep going on about - if dynamic Groovy does not pick up
>> the RHS type for final, I need to keep my current code, or force
>> framework users to use @CompileStatic on all Table derived classes,
>> if they want to define table columns in the most elegant and concise
>> way... :-)
>
> for "final x = ..." the exact type of x is in dynamic mode actually
> totally not relevant. There is no reassignment, so that problem is out
> here. But if we forget about that, then there is no difference between
> "final x" and "def x". I know cases where it could make a difference,
> but they do not exist in Groovy yet. so what exactly is final x
> supposed to do different than def x besides the reassignment?

class Foo {
     final f0 = new FoorchterlichLongerNome(...) // class field c0 will
have type Object; when analyzing the class using reflection, field
cannot be found by looking for fields/properties of type Col
     final FoorchterlichLongerNome f1 = new FoorchterlichLongerNome(...)
// class field will be of type FoorchterlichLongerNome; this is the
behavior I would wish for without explicitely being required to give
FoorchterlichLongerNome , even in the dynamic case, for simple
expressions (as listed above)
}

I totally understand if you do not agree with me - maybe there is
nothing here but to agree to differ...
mg



1234