Possible New Groovy Features...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
26 messages Options
123
MG
Reply | Threaded
Open this post in threaded view
|

Possible New Groovy Features...

MG
Hi,

before I create change requests, I wanted to ask for some quick feedback on the following potential new Groovy features (I apologize beforehand, if any of these are already covered in some way, and I missed it, or if they have been discussed before, etc - just throwing ideas that I find useful out there :-) ):
  1. Named Paramters: I already posted that feature request here. The most plain vanilla support (support the <name>:<value>, <name>:<value>, ... syntax to give named ctor/method args) would already cover 99% of applications here, I think. The imho most problematic feedback was external libraries without debug information - my question would be how frequently such libraries occur in practice (I personally have never pressed Ctrl+B in IntelliJ and not gotten a method decompile result with parameter names) ?
  2. Support making all method/ctor parameters final by default through "autofinal" Groovy compiler flag:
    Foo(int x, String s) { // final keyword is auto added to all parameters, if compiler flag is set, i.e. this automatically becomes Foo(final int x, final String s)
    this.x = x; this.s
    }
    Rationale: Even if Groovy source samples use def instead of final a lot, parameters (and variables) are, according to my experience, most of the time actually final in practice (In the few cases where one needs to modify a parameter, it can immediately be assigned to a variable). This feature would reduce the source code clutter that comes from the need to qualify parameters as final all the time.
  3. Deduce the type of final fields from their assigned value:
    class Foo {
    final device = new PrinterDevice(...) // device field will have type PrinterDevice instead of Object when reflection is used on class Foo
    }
    Rationale: While IntelliJ does a good job at deducing the type of final fields, it would still be better if the Groovy language itself would use the more specialized type here, for e.g. reflection purposes
  4. Introduce a "var" (o.s.) keyword that allows deduction of type through assignment:
    var device = new PrinterDevice(...) // device variable will have type PrinterDevice without the need to explictely state that
    Rationale: This is a well known feature of other languages, that reduces the need to explictely define the type of variables.
  5. Always allow ctor calls without new keyword:
    final foo = Foo("abc") // creates a new Foo instance by calling Foo class ctor with signature
    Rationale: new keyword was necessary in C++ to distinguish heap vs stack variable allocation. No such need exists in Groovy, so the keyword just clutters the source code. Naming convention of method names being always lowercase prevents name clashes with methods.
  6. "Variable plus Name" support: One of the most useful macros I used in C++ was NV(x), where I passed a variable, and created a NamedVariable instance, which was automatically passed the name and the value of the variable (through simple macro stringify). I would love to see something similar in Groovy.
    Rationale: Most important application is DRY creation of debug output, e.g.:
    println NV(longVariableName)  // equivalent result to println "longVariableName=$longVariableName" avoding the potential classical copy & paste error "longVariableName=$longrVariableName"
  7. Support break/continue to work as if a closure was a block construct, e.g. through an annotation on the Closure parameter:
    sqe.forEachRow("select * from PERSON") { final row ->
    if(row.TAG == 0) { continue } // Move to next iteration in forEachRow iteration over PERSON table
    if(row.TAG == 1) { break } // Return form closure & return from forEachRow (effectively stopping to iterate over PERSON table rows, continuing after the method call)
    }
    Rationale: Groovy's support for giving a Closure as the last argument outside of the parameter brackets is one of its most neat features. Supporting break/continue with expected (least surprise) semantics inside of such closures, would make this feature complete.
    (Note: I have implemented support for a "BreakLoopException" in my code, so that the closure body can signal a break to e.g. forEachRow, but that is still quite an akward solution, that breaks the illusion that forEachRow works like a regular for-each statement)
  8. CompileStatic byte code call compatibility with Java: I have included this, since I saw it on the mailing list here, and I always tell everyone that Groovy is basically a drop in replacement for Java, which in this case, if obfuscation is part of the game, does not seem to be the case (in addition my son has also started to mod Minecraft a bit, and I wanted to use this to introduce him to Groovy - after he has suffered through a bit of Java ;-) ).
mg


Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features...

paulk_asert
Hi Markus,

Thanks for your suggestions. Some neat ideas in your suggestions! Just a general comment to start off with...

With language design, it's often the details which are important, so I'd suggest rather than going straight from this email to a bunch of PRs, you'd create separate Jira issues for those items you want to pursue and flesh out the design a little more - it's often the dealing with backwards compatibility and handling error situations that take up more of the design time than the actual feature itself. Having said that, please don't be put off with the extra work. We usually follow the same process ourselves and find the extra discipline helps all round. For simple non-controversial enhancements, not much detail might be needed but in other cases, there might be lots of details that need to be handled that might not be apparent at first - plus a Jira issue is a good place for us to suggest hints on how to get started.

Some more comments inline below ...

Cheers, Paul.

On Mon, Aug 21, 2017 at 6:25 AM, MG <[hidden email]> wrote:
Hi,

before I create change requests, I wanted to ask for some quick feedback on the following potential new Groovy features (I apologize beforehand, if any of these are already covered in some way, and I missed it, or if they have been discussed before, etc - just throwing ideas that I find useful out there :-) ):
  1. Named Parameters: I already posted that feature request here. The most plain vanilla support (support the <name>:<value>, <name>:<value>, ... syntax to give named ctor/method args) would already cover 99% of applications here, I think. The imho most problematic feedback was external libraries without debug information - my question would be how frequently such libraries occur in practice (I personally have never pressed Ctrl+B in IntelliJ and not gotten a method decompile result with parameter names) ?
It is certainly worth fleshing this out a little more. Such support has been considered in the past [1,2] but that was prior to JEP118[3,4] being finalized and we decided to wait. Some of the backwards compatibility issues mentioned in that thread still remain and we'd need to spell out what we are planning in that regard (that affects what version this might be merged into).  I'll also note that there are some tricks that IDEs might use (looking at source code, javadoc etc.) that we would not likely pursue. There are also some pre java8 tricks that can be used [5,6,7] but I think we would more likely want to pursue the JEP118 approach - though do feel free to experiment if you think those approaches might be useful - we'd need to weigh up what additional libraries that might required to be available for basic compilation. I have less optimism about whether JEP118 metadata information will be available anytime soon - doesn't mean we shouldn't provide support in the meantime for the situations where it does exist. I did a sample size of 1 by downloading the latest Guava and it wasn't available in that library - also the Java libraries themselves didn't have that information last time I checked. Also, there is an old issue that could be useful that would work for constructors even on old JDK versions using a JavaBean annotation[8] though again I don't think widely used. Also, we'd need to understand if there are any impacts on Groovy's mixed Map/positional notation and whether true optional arguments support would be included[9].


  1. Support making all method/ctor parameters final by default through "autofinal" Groovy compiler flag:
    Foo(int x, String s) { // final keyword is auto added to all parameters, if compiler flag is set, i.e. this automatically becomes Foo(final int x, final String s)
    this.x = x; this.s
    }
    Rationale: Even if Groovy source samples use def instead of final a lot, parameters (and variables) are, according to my experience, most of the time actually final in practice (In the few cases where one needs to modify a parameter, it can immediately be assigned to a variable). This feature would reduce the source code clutter that comes from the need to qualify parameters as final all the time.
You can already leave off the "clutter" and apply a CodeNarc rule[1] to detect "bad" style. Also, it would be an easy task to create an @AutoFinal local transform which could then be automatically applied using a compiler customizer. I think going further with a dedicated compiler flag would be a later step if such a local transform became extremely popular.

[1] http://codenarc.sourceforge.net/codenarc-rules-convention.html#ParameterReassignment
  1. Deduce the type of final fields from their assigned value:
  2. class Foo {
    final device = new PrinterDevice(...) // device field will have type PrinterDevice instead of Object when reflection is used on class Foo
    }
    Rationale: While IntelliJ does a good job at deducing the type of final fields, it would still be better if the Groovy language itself would use the more specialized type here, for e.g. reflection purposes
With @Typechecked or @CompileStatic type inferencing is going to be in play. During debugging the runtime type is going to be available. What "reflective purposes" did you have in mind?
  1. Introduce a "var" (o.s.) keyword that allows deduction of type through assignment:
    var device = new PrinterDevice(...) // device variable will have type PrinterDevice without the need to explictely state that
    Rationale: This is a well known feature of other languages, that reduces the need to explictely define the type of variables.
How is this different to the current type inferencing? 
  1. Always allow ctor calls without new keyword:
    final foo = Foo("abc") // creates a new Foo instance by calling Foo class ctor with signature
    Rationale: new keyword was necessary in C++ to distinguish heap vs stack variable allocation. No such need exists in Groovy, so the keyword just clutters the source code. Naming convention of method names being always lowercase prevents name clashes with methods.
 A partial solution to this is available via @Newify. As far as I know, @Newify hasn't been super popular, so we'd need to think carefully about introducing this.
  1. "Variable plus Name" support: One of the most useful macros I used in C++ was NV(x), where I passed a variable, and created a NamedVariable instance, which was automatically passed the name and the value of the variable (through simple macro stringify). I would love to see something similar in Groovy. Rationale: Most important application is DRY creation of debug output, e.g.:  println NV(longVariableName)  // equivalent result to println "longVariableName=$longVariableName" avoding the potential classical copy & paste error "longVariableName=$longrVariableName"
Sounds like a possible candidate for using Macros? 
  1. Support break/continue to work as if a closure was a block construct, e.g. through an annotation on the Closure parameter:
    sqe.forEachRow("select * from PERSON") { final row ->
    if(row.TAG == 0) { continue } // Move to next iteration in forEachRow iteration over PERSON table
    if(row.TAG == 1) { break } // Return form closure & return from forEachRow (effectively stopping to iterate over PERSON table rows, continuing after the method call)
    }
    Rationale: Groovy's support for giving a Closure as the last argument outside of the parameter brackets is one of its most neat features. Supporting break/continue with expected (least surprise) semantics inside of such closures, would make this feature complete.
    (Note: I have implemented support for a "BreakLoopException" in my code, so that the closure body can signal a break to e.g. forEachRow, but that is still quite an akward solution, that breaks the illusion that forEachRow works like a regular for-each statement)
Non-local transfers (break/continue/non-local returns) have been discussed before[1] but perhaps worth revisiting now that Scala supports the non-local return approach using Exceptions[2] and Kotlin has labelled returns in lambda functions[3]. The main issue to keep in mind would be backwards compatibility/breaking changes.

[1] http://blackdragsview.blogspot.com.au/2006/09/non-local-transfers-in-groovy-90.html
[2] http://dev.bizo.com/2010/01/scala-supports-non-local-returns.html
  1. CompileStatic byte code call compatibility with Java: I have included this, since I saw it on the mailing list here, and I always tell everyone that Groovy is basically a drop in replacement for Java, which in this case, if obfuscation is part of the game, does not seem to be the case (in addition my son has also started to mod Minecraft a bit, and I wanted to use this to introduce him to Groovy - after he has suffered through a bit of Java ;-) ).
There are definitely edge cases where @CompileStatic falls back to dynamic calls which we want to improve.
mg



MG
Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features...

MG
Hi Paul,

thanks for your reply. If I had known you were gonna hit back with so much detail, I would have gone with splitting my mail into multiple parts (but didn't want to spam the mailing list) ;-)
I will read up on your links and reply in smaller chunks...

Cheers,
Markus


On 21.08.2017 04:30, Paul King wrote:
Hi Markus,

Thanks for your suggestions. Some neat ideas in your suggestions! Just a general comment to start off with...

With language design, it's often the details which are important, so I'd suggest rather than going straight from this email to a bunch of PRs, you'd create separate Jira issues for those items you want to pursue and flesh out the design a little more - it's often the dealing with backwards compatibility and handling error situations that take up more of the design time than the actual feature itself. Having said that, please don't be put off with the extra work. We usually follow the same process ourselves and find the extra discipline helps all round. For simple non-controversial enhancements, not much detail might be needed but in other cases, there might be lots of details that need to be handled that might not be apparent at first - plus a Jira issue is a good place for us to suggest hints on how to get started.

Some more comments inline below ...

Cheers, Paul.

On Mon, Aug 21, 2017 at 6:25 AM, MG <[hidden email]> wrote:
Hi,

before I create change requests, I wanted to ask for some quick feedback on the following potential new Groovy features (I apologize beforehand, if any of these are already covered in some way, and I missed it, or if they have been discussed before, etc - just throwing ideas that I find useful out there :-) ):
  1. Named Parameters: I already posted that feature request here. The most plain vanilla support (support the <name>:<value>, <name>:<value>, ... syntax to give named ctor/method args) would already cover 99% of applications here, I think. The imho most problematic feedback was external libraries without debug information - my question would be how frequently such libraries occur in practice (I personally have never pressed Ctrl+B in IntelliJ and not gotten a method decompile result with parameter names) ?
It is certainly worth fleshing this out a little more. Such support has been considered in the past [1,2] but that was prior to JEP118[3,4] being finalized and we decided to wait. Some of the backwards compatibility issues mentioned in that thread still remain and we'd need to spell out what we are planning in that regard (that affects what version this might be merged into).  I'll also note that there are some tricks that IDEs might use (looking at source code, javadoc etc.) that we would not likely pursue. There are also some pre java8 tricks that can be used [5,6,7] but I think we would more likely want to pursue the JEP118 approach - though do feel free to experiment if you think those approaches might be useful - we'd need to weigh up what additional libraries that might required to be available for basic compilation. I have less optimism about whether JEP118 metadata information will be available anytime soon - doesn't mean we shouldn't provide support in the meantime for the situations where it does exist. I did a sample size of 1 by downloading the latest Guava and it wasn't available in that library - also the Java libraries themselves didn't have that information last time I checked. Also, there is an old issue that could be useful that would work for constructors even on old JDK versions using a JavaBean annotation[8] though again I don't think widely used. Also, we'd need to understand if there are any impacts on Groovy's mixed Map/positional notation and whether true optional arguments support would be included[9].


  1. Support making all method/ctor parameters final by default through "autofinal" Groovy compiler flag:
    Foo(int x, String s) { // final keyword is auto added to all parameters, if compiler flag is set, i.e. this automatically becomes Foo(final int x, final String s)
    this.x = x; this.s
    }
    Rationale: Even if Groovy source samples use def instead of final a lot, parameters (and variables) are, according to my experience, most of the time actually final in practice (In the few cases where one needs to modify a parameter, it can immediately be assigned to a variable). This feature would reduce the source code clutter that comes from the need to qualify parameters as final all the time.
You can already leave off the "clutter" and apply a CodeNarc rule[1] to detect "bad" style. Also, it would be an easy task to create an @AutoFinal local transform which could then be automatically applied using a compiler customizer. I think going further with a dedicated compiler flag would be a later step if such a local transform became extremely popular.

[1] http://codenarc.sourceforge.net/codenarc-rules-convention.html#ParameterReassignment
  1. Deduce the type of final fields from their assigned value:
  2. class Foo {
    final device = new PrinterDevice(...) // device field will have type PrinterDevice instead of Object when reflection is used on class Foo
    }
    Rationale: While IntelliJ does a good job at deducing the type of final fields, it would still be better if the Groovy language itself would use the more specialized type here, for e.g. reflection purposes
With @Typechecked or @CompileStatic type inferencing is going to be in play. During debugging the runtime type is going to be available. What "reflective purposes" did you have in mind?
  1. Introduce a "var" (o.s.) keyword that allows deduction of type through assignment:
    var device = new PrinterDevice(...) // device variable will have type PrinterDevice without the need to explictely state that
    Rationale: This is a well known feature of other languages, that reduces the need to explictely define the type of variables.
How is this different to the current type inferencing? 
  1. Always allow ctor calls without new keyword:
    final foo = Foo("abc") // creates a new Foo instance by calling Foo class ctor with signature
    Rationale: new keyword was necessary in C++ to distinguish heap vs stack variable allocation. No such need exists in Groovy, so the keyword just clutters the source code. Naming convention of method names being always lowercase prevents name clashes with methods.
 A partial solution to this is available via @Newify. As far as I know, @Newify hasn't been super popular, so we'd need to think carefully about introducing this.
  1. "Variable plus Name" support: One of the most useful macros I used in C++ was NV(x), where I passed a variable, and created a NamedVariable instance, which was automatically passed the name and the value of the variable (through simple macro stringify). I would love to see something similar in Groovy. Rationale: Most important application is DRY creation of debug output, e.g.:  println NV(longVariableName)  // equivalent result to println "longVariableName=$longVariableName" avoding the potential classical copy & paste error "longVariableName=$longrVariableName"
Sounds like a possible candidate for using Macros? 
  1. Support break/continue to work as if a closure was a block construct, e.g. through an annotation on the Closure parameter:
    sqe.forEachRow("select * from PERSON") { final row ->
    if(row.TAG == 0) { continue } // Move to next iteration in forEachRow iteration over PERSON table
    if(row.TAG == 1) { break } // Return form closure & return from forEachRow (effectively stopping to iterate over PERSON table rows, continuing after the method call)
    }
    Rationale: Groovy's support for giving a Closure as the last argument outside of the parameter brackets is one of its most neat features. Supporting break/continue with expected (least surprise) semantics inside of such closures, would make this feature complete.
    (Note: I have implemented support for a "BreakLoopException" in my code, so that the closure body can signal a break to e.g. forEachRow, but that is still quite an akward solution, that breaks the illusion that forEachRow works like a regular for-each statement)
Non-local transfers (break/continue/non-local returns) have been discussed before[1] but perhaps worth revisiting now that Scala supports the non-local return approach using Exceptions[2] and Kotlin has labelled returns in lambda functions[3]. The main issue to keep in mind would be backwards compatibility/breaking changes.

[1] http://blackdragsview.blogspot.com.au/2006/09/non-local-transfers-in-groovy-90.html
[2] http://dev.bizo.com/2010/01/scala-supports-non-local-returns.html
  1. CompileStatic byte code call compatibility with Java: I have included this, since I saw it on the mailing list here, and I always tell everyone that Groovy is basically a drop in replacement for Java, which in this case, if obfuscation is part of the game, does not seem to be the case (in addition my son has also started to mod Minecraft a bit, and I wanted to use this to introduce him to Groovy - after he has suffered through a bit of Java ;-) ).
There are definitely edge cases where @CompileStatic falls back to dynamic calls which we want to improve.
mg




MG
Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features... - Auto final-ize

MG
In reply to this post by paulk_asert
Hi Paul,

On 21.08.2017 04:30, Paul King wrote:

Support making all method/ctor parameters final by default through "autofinal" Groovy compiler flag:
  1. Foo(int x, String s) { // final keyword is auto added to all parameters, if compiler flag is set, i.e. this automatically becomes Foo(final int x, final String s)
    this.x = x; this.s
    }
    Rationale: Even if Groovy source samples use def instead of final a lot, parameters (and variables) are, according to my experience, most of the time actually final in practice (In the few cases where one needs to modify a parameter, it can immediately be assigned to a variable). This feature would reduce the source code clutter that comes from the need to qualify parameters as final all the time.
You can already leave off the "clutter" and apply a CodeNarc rule[1] to detect "bad" style.

you are not a big fan of using final, I gather ;-)
When I picked Groovy for the framework I am developing, I started writing code in the typical Groovy style used e.g. on the Groovy webpage and mrhaki: def everywhere, no final. But at some point the C++ developer in me kicked in, and I started to ask myself, why final was not used instead of def, since in 99.999% of cases, no reassignment of variables or parameters occurs ? Apart from making the code easier to read & safer, it also allows compiler optimizations (and in the absence of a true const-keyword, at least for fundamental data types it has the same effect). So I started using final, and reapplying it to the code I wrote before. For methods with a large number of parameters this makes the method definition really long, and does not really improve readability. So auto-applying final imho really makes sense, at least in my case (but I am convinced it would for most Groovy developers, if it is easily available).

Also, it would be an easy task to create an @AutoFinal local transform which could then be automatically applied using a compiler customizer. I think going further with a dedicated compiler flag would be a later step if such a local transform became extremely popular.

Never found the need to do my own AST transforms in Groovy - do you maybe have a pointer to a current tutorial on how to get started for me ? Since you mentioned macros in your reply, I first went "Do we have these in Groovy ?", then I found I checked out the 2.5 macro description - do you think it would be worth waiting for 2.5 to become stable to be able to use macros for this functionality ?

Cheers,
Markus



MG
Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features... - Deduce the type of final fields from their assigned value

MG
In reply to this post by paulk_asert
Hi Paul,

On 21.08.2017 04:30, Paul King wrote:
Deduce the type of final fields from their assigned value:
class Foo {
final device = new PrinterDevice(...) // device field will have type PrinterDevice instead of Object when reflection is used on class Foo
}
Rationale: While IntelliJ does a good job at deducing the type of final fields, it would still be better if the Groovy language itself would use the more specialized type here, for e.g. reflection purposes
With @Typechecked or @CompileStatic type inferencing is going to be in play. During debugging the runtime type is going to be available. What "reflective purposes" did you have in mind?

In my framework I iterate over the fields of classes, which are of type Object, if the have been defined in a compact way using just final, without an explicit type - it would be helpful to have the type here.
And in general it just feels like a lost opportunity that final fields/variables do not auto get the type of their assigned value - having more information available is never bad.
Of course I am talking about this naively from a user's perspective: Do you think adding this would a) be hard / time intensive (naively I would have thought no), b) break backwards comptability (since the final variable/field cannot be reassigned... (?))...

Cheers,
Markus



MG
Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features... - var Keyword

MG
In reply to this post by paulk_asert
Hi Paul,

On 21.08.2017 04:30, Paul King wrote:

Introduce a "var" (o.s.) keyword that allows deduction of type through assignment:
var device = new PrinterDevice(...) // device variable will have type PrinterDevice without the need to explictely state that
Rationale: This is a well known feature of other languages, that reduces the need to explictely define the type of variables.

How is this different to the current type inferencing?

The variable/field will have the type of the initally assigned value (instead of Object when using def), therefore one cannot accidentially assign any other type to it.

Cheers,
Markus


MG
Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features... - ctor calls without new keyword

MG
In reply to this post by paulk_asert
Hi Paul,

On 21.08.2017 04:30, Paul King wrote:
Always allow ctor calls without new keyword:

final foo = Foo("abc") // creates a new Foo instance by calling Foo class ctor with signature
Rationale: new keyword was necessary in C++ to distinguish heap vs stack variable allocation. No such need exists in Groovy, so the keyword just clutters the source code. Naming convention of method names being always lowercase prevents name clashes with methods.

 A partial solution to this is available via @Newify. As far as I know, @Newify hasn't been super popular, so we'd need to think carefully about introducing this.


I am not surprised that the @Newify annotation (http://docs.groovy-lang.org/latest/html/api/groovy/lang/Newify.html) is not popular: When I first read the Groovy documentation (somewhere around 1.8.x) and came across @Newify, I was "Yes - fanta... wait... you have to do what ?". It felt like a feature that was introduced to kill it off immediately...
The Ruby Foo.new(...) syntax falls short for me, since it basically just moves the "new" String around, i.e. it does not make the code much more readable / compact. And for the Foo(...) style, you have to give the classes it shall work for explicitely in the @Newify, which is imho too cumbersome.

If @Newify with Foo(...) ctor calls would work without arguments, one could apply it through a compiler customizer, so can you tell me the rationale for not going down that route (and if the rationale ist still valid in 2017 ;-) ), together with the cryptic "The annotation is intended to be used sparingly" in the @Newify doc ?

For me, getting rid of "new" would be as Groovy as e.g. dropping the semicolon end of line character - which was not necessary since the days of K&R - or being able to give the Closure argument like a block construct :-)

Now crush my hopes with some backward-compatibility-Groovy-insider-error-situations-handler-reason,
Ma;-)rkus


Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features... - ctor calls without new keyword

jwagenleitner
Just thought I'd mention list and map constructors [1], with those you can not only leave out the `new` keyword but also leave off the type (at least on the RHS)

Foo foo = ['abc']


On Tue, Aug 22, 2017 at 4:16 PM, MG <[hidden email]> wrote:
Hi Paul,

On 21.08.2017 04:30, Paul King wrote:
Always allow ctor calls without new keyword:

final foo = Foo("abc") // creates a new Foo instance by calling Foo class ctor with signature
Rationale: new keyword was necessary in C++ to distinguish heap vs stack variable allocation. No such need exists in Groovy, so the keyword just clutters the source code. Naming convention of method names being always lowercase prevents name clashes with methods.

 A partial solution to this is available via @Newify. As far as I know, @Newify hasn't been super popular, so we'd need to think carefully about introducing this.


I am not surprised that the @Newify annotation (http://docs.groovy-lang.org/latest/html/api/groovy/lang/Newify.html) is not popular: When I first read the Groovy documentation (somewhere around 1.8.x) and came across @Newify, I was "Yes - fanta... wait... you have to do what ?". It felt like a feature that was introduced to kill it off immediately...
The Ruby Foo.new(...) syntax falls short for me, since it basically just moves the "new" String around, i.e. it does not make the code much more readable / compact. And for the Foo(...) style, you have to give the classes it shall work for explicitely in the @Newify, which is imho too cumbersome.

If @Newify with Foo(...) ctor calls would work without arguments, one could apply it through a compiler customizer, so can you tell me the rationale for not going down that route (and if the rationale ist still valid in 2017 ;-) ), together with the cryptic "The annotation is intended to be used sparingly" in the @Newify doc ?

For me, getting rid of "new" would be as Groovy as e.g. dropping the semicolon end of line character - which was not necessary since the days of K&R - or being able to give the Closure argument like a block construct :-)

Now crush my hopes with some backward-compatibility-Groovy-insider-error-situations-handler-reason,
Ma;-)rkus



Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features... - Deduce the type of final fields from their assigned value

paulk_asert
In reply to this post by MG
It might be something that could work with @CompileStatic. For dynamic Groovy, I am not sure this can be done. Consider the following example which, although is dubious style, is valid Groovy:

Date.metaClass.constructor = { 42 }
final result = new Date()
assert result instanceof Integer
assert result == 42

Cheers, Paul.

On Wed, Aug 23, 2017 at 8:45 AM, MG <[hidden email]> wrote:
Hi Paul,

On 21.08.2017 04:30, Paul King wrote:
Deduce the type of final fields from their assigned value:
class Foo {
final device = new PrinterDevice(...) // device field will have type PrinterDevice instead of Object when reflection is used on class Foo
}
Rationale: While IntelliJ does a good job at deducing the type of final fields, it would still be better if the Groovy language itself would use the more specialized type here, for e.g. reflection purposes
With @Typechecked or @CompileStatic type inferencing is going to be in play. During debugging the runtime type is going to be available. What "reflective purposes" did you have in mind?

In my framework I iterate over the fields of classes, which are of type Object, if the have been defined in a compact way using just final, without an explicit type - it would be helpful to have the type here.
And in general it just feels like a lost opportunity that final fields/variables do not auto get the type of their assigned value - having more information available is never bad.
Of course I am talking about this naively from a user's perspective: Do you think adding this would a) be hard / time intensive (naively I would have thought no), b) break backwards comptability (since the final variable/field cannot be reassigned... (?))...

Cheers,
Markus




Reply | Threaded
Open this post in threaded view
|

Re: Possible New Groovy Features... - Auto final-ize

paulk_asert
In reply to this post by MG
Forgot the list the first time.

On Thu, Aug 24, 2017 at 8:44 PM, Paul King <[hidden email]> wrote:


On Wed, Aug 23, 2017 at 8:32 AM, MG <[hidden email]> wrote:
Hi Paul,

On 21.08.2017 04:30, Paul King wrote:

Support making all method/ctor parameters final by default through "autofinal" Groovy compiler flag:
  1. Foo(int x, String s) { // final keyword is auto added to all parameters, if compiler flag is set, i.e. this automatically becomes Foo(final int x, final String s)
    this.x = x; this.s
    }
    Rationale: Even if Groovy source samples use def instead of final a lot, parameters (and variables) are, according to my experience, most of the time actually final in practice (In the few cases where one needs to modify a parameter, it can immediately be assigned to a variable). This feature would reduce the source code clutter that comes from the need to qualify parameters as final all the time.
You can already leave off the "clutter" and apply a CodeNarc rule[1] to detect "bad" style.

you are not a big fan of using final, I gather ;-)

It's not a case of being a fan of a particular style. Groovy supports final using the final keyword and we'd want a very good reason to change that now. So I am just taking the Devil's advocate point of view saying that the breaking change and difference to Java are possibly too big given what is currently supported. If we were starting a language from scratch and cared a little less about being somewhat similar to Java, it might be a totally different story.
 
When I picked Groovy for the framework I am developing, I started writing code in the typical Groovy style used e.g. on the Groovy webpage and mrhaki: def everywhere, no final. But at some point the C++ developer in me kicked in, and I started to ask myself, why final was not used instead of def, since in 99.999% of cases, no reassignment of variables or parameters occurs ? Apart from making the code easier to read & safer, it also allows compiler optimizations (and in the absence of a true const-keyword, at least for fundamental data types it has the same effect). So I started using final, and reapplying it to the code I wrote before. For methods with a large number of parameters this makes the method definition really long, and does not really improve readability. So auto-applying final imho really makes sense, at least in my case (but I am convinced it would for most Groovy developers, if it is easily available).

Also, it would be an easy task to create an @AutoFinal local transform which could then be automatically applied using a compiler customizer. I think going further with a dedicated compiler flag would be a later step if such a local transform became extremely popular.

Never found the need to do my own AST transforms in Groovy - do you maybe have a pointer to a current tutorial on how to get started for me ? Since you mentioned macros in your reply, I first went "Do we have these in Groovy ?", then I found I checked out the 2.5 macro description - do you think it would be worth waiting for 2.5 to become stable to be able to use macros for this functionality ?

For a tutorial, I don't have anything that googling "groovy create local AST transform" wouldn't give you. The online docs and Groovy in Action would be my picks. I'd suggest an AST transform over a macro for this use case. I'd also add that Groovy's final variable analyser itself (a new feature in 2.5) still has a few unfinished parts if you are looking for something that needs doing.


Cheers, Paul.
 

Cheers,
Markus





123