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

2018-03-12 Thread MG
PS: Just wanted to ask what you think about the idea of making var a 
compile time error in dynamic Groovy, with an error message (see 
previous posting) that points the developer to @CompileStatic ?

My line of thinking is, that
# var makes no sense in dynamic Groovy in the case of var === def (in a 
sense it is a ruse - like replacing every type the user gives with def)
# Someone who wants to port code from Java is actually better served by 
static Groovy than by dynamic, since

## It is semantically closer to what he is used to
## Performance characteristics might also be closer to what he expects 
(I know dynamic Groovy is very fast, and can be faster than static, so 
emphasis is on "characteristics")
## ...and he will avoid the error of starting with dynamic Groovy 
everywhere (because it looks like static Java), when in fact he would 
probably be better off using dynamic code only in places where it is 
actually required
*** thereby avoding surprises like e.g. null.forEach { ... } being a 
valid dynamic Groovy expression and therefore not throwing, not even at 
runtime ;-)
# (It would allow to introduce var in dynamic Groovy later on, with a 
better semantic than var === def)


Cheers,
mg



On 12.03.2018 07:52, Jochen Theodorou wrote:

On 11.03.2018 17:29, MG wrote:



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


the difference is that it is not supposed to do that in static mode ;)

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


Integer foo(int i) {1}
String  foo(String s) {"2"}

def bar (x) {
  return foo(x)
}

at the callsite in bar you cannot tell if foo(int) or foo(String) is 
supposed to be called. Methods at runtime increase the problem, but it 
is not unique to them. And it does not always have to be an override 
in the classic sense either


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

}


ah, I was talking about local variables, not about fields/properties. 
For me that style is more the exception. And once you move the code to 
the constructor you do not get inference for the field/property 
anymore. So its good only for some very specific cases. And for those 
to make a difference in the dynamic mode...


bye Jochen






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

2018-03-12 Thread Jochen Theodorou

On 11.03.2018 17:29, MG wrote:



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


the difference is that it is not supposed to do that in static mode ;)

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


Integer foo(int i) {1}
String  foo(String s) {"2"}

def bar (x) {
  return foo(x)
}

at the callsite in bar you cannot tell if foo(int) or foo(String) is 
supposed to be called. Methods at runtime increase the problem, but it 
is not unique to them. And it does not always have to be an override in 
the classic sense either


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

}


ah, I was talking about local variables, not about fields/properties. 
For me that style is more the exception. And once you move the code to 
the constructor you do not get inference for the field/property anymore. 
So its good only for some very specific cases. And for those to make a 
difference in the dynamic mode...


bye Jochen



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

2018-03-11 Thread 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





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

2018-03-11 Thread Jochen Theodorou

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


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

2018-03-10 Thread 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 @daniil.ovchinni...@jetbrains.com: 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* >
Date: Sat, Mar 10, 2018 at 7:19 AM
Subject: Re: About supporting `var` of Java10+
To: pa...@asert.com.au 

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

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

2018-03-10 Thread 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* >
Date: Sat, Mar 10, 2018 at 7:19 AM
Subject: Re: About supporting `var` of Java10+
To: pa...@asert.com.au 

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