Please use this page to document all the ideas and wishes you'd like to see in Groovy.
Non-breaking Switch Enhancements
Objective: get rid of a lot of if then else statements; eliminate unnecessary syntax; no impact on "java-like" groovy code.
Multiple parameters/targets
| Code Block |
|---|
// multiple parameter switch
// '?' == true/any
def x = { a, b -> switch(a,b) {
case (0, 0) : return 0
case (0, 1), (1, 0) : return 1
case (1, ?), (?, 1) : return 2
default : return 3
}}
|
Alternate '->' Syntax, Optional 'default', Assign Result
| Code Block |
|---|
// in a switch '->' implies break,
// 'default' is optional,
// and they can have a result
def x = { a ->
switch (a) {
case 0 -> println 'a'
case 1 -> println 'b'
-> println 'c'
}
def b = switch(a) {
case 0 -> 'a'
case 1 -> 'b'
-> 'c'
}
}
|
Combine "Multiparameter" and "Alternate Syntax" with Abbreviated form in Closures
| Code Block |
|---|
// a short form of the above for function pattern matching
def x = { a, b
case (0, 0) -> 0
case (0, 1),
(1, 0) -> 1
case (1, ?),
(?, 1) -> 2
default -> 3
}
|
Here the '->' form implies 'return' instead of 'break' (same result at this level)
Another example:
| Code Block |
|---|
// case works as it does currently, executing the closure or calling isCase()
def qsort = { ls
case {ls.size() < 2} -> ls
->
def (x, xs) = [ls.head(), ls.tail()]
def smaller, larger = []
xs.each { it<=x ? smaller<<it : larger<<it }
qsort(smaller) + x + qsort(larger)
}
|
Here you can see the special "case" is executed when the list size is less than 2, otherwise it looks like a normal closure.
The above proposal does not break any existing code, does not add any keywords, does not break compatibility with java ("paste java in to groovy and it work", etc).
The multi-parameter switch statement and '->' in a switch so it has a result is where the core of the work would be. The 'case' statement on a closure definition for pattern matching like capability is just syntactical sugar.
--krsmes (Apr 2010)
- New function for integers to reverse bits.
- Concatenate string with null object. 'Test'+null will produce 'Test'.
- Function/Global method 'NVL'. This method avoid null/empty string value of object. E.g. NVL(null,'Test')='Test' and NVL('','Test')='Test'
- Joining of list without null elements.
e.g. [null,'Hello','world',null].join(' ') will produce 'Hello world'
- Simple and Robust way of executing external processes instead of using ProcessBuilder. Make the convenient string.execute() handle blocked IO streams / threading so users are not required know or understand about ProcessBuilder
- More Enumerable methods for lists, arrays and maps (like map, pluck, invoke, ...)
- Make logical operators (||, &&...) return the value instead of the boolean equivalent
eg.Code Block def x = '' || 'test' assert x == 'test' def x = null || 15 assert x == 15
- Make map creation more versatile. Add constructors that allow creation of a map from 2 collections "HashMap(keys, values)" or a list of entries "HashMap(itemlist)".
- Make a list and create an auto mapping:
eg.
| Code Block |
|---|
//Today: def list = ["key":"value", 1:1, 2:2, "noAuto":"noAuto"] print(list[1]) // will print 1 //Would like to have: def autoMapList = ["key":"value", 1, 2, "auto"] print(autoMapList[1]) // will print 1 |
- would like methods to return more than one return value (a la ruby)
Code Block //Today: def mytest { return [1,2] } c = mytest() a = c[0] b = c[1] wanted behavior: def mytest { return 1,2 } a,b = mytest()
Property reference operator
Groovy 1.0 already has the method reference operator:
| Code Block |
|---|
class X {
def doSomething() { println "hello" }
}
def obj = new X()
def methRef = obj.&doSomething
methRef()
|
However we do not have anything similar for properties. i.e. we should be able to get a reference to a wrapper object for any object property, and be able to get and set the property via the reference, and get the original property name and owning bean:
| Code Block |
|---|
class X {
def someValue
}
def obj = new X()
def propRef = obj.&someValue // same syntax, but runtime knows it is a property
println propRef.value
propRef.value = 999
println propRef.name // outputs "someValue"
assert propRef.object == obj
// static property equivalent
def propRef = X.&someValue
// Now you need to pass in an instance
propRef.setValue( new X(), 123)
|
This would be useful in Grails and other apps that need the user to specify in their code a reference to another propery, for example in GORM declaring the list of "embedded" properties:
class AddressBookEntry
Property access in groovy is not problematic using GPath or subscript operator anyway, so this may not seem so useful. However if we could get some compile-time checking of the validity of the property that would be a nice win. Perhaps combining with the @ operator:
| Code Block |
|---|
class AddressBookEntry {
Address home
Address work
String name
static embedded = [ &@home, &@work ]
}
|
Altho a tad heiroglyphic, this would allow the compiler to ensure that "home" and "work" do exist as declared properties on the class or its ancestors, and hence fail fast.
named parameters everywhere
the proposal is that for functions defined inside groovy or where the debug information is availlable can be called with the map construct to provide named parameter calling everywhere
| Code Block |
|---|
void helloworld(name, title) {println "hello $title $name"}
can be called as
helloworld( title:"mr.", name:"koen" )
|
this feature would largely improve general readability of code and imho very often enough information should be availlable to perform the matching (certainly for groovy functions, very often for java binaries with appropriate debug information)
smarter nulls
| Code Block |
|---|
def hello = "hello" def test = null println "$hello$test" |
should print "hello" iso "hellonull"
variable constraints
Keep dynamic typing while adding real type safety with constraints on variables that all must be true. Though not all these constraints are actually useful they are there for illustrative purposes.
| Code Block |
|---|
percent : as Integer, >= 0, <= 100 total : != 0 ... percent = num/total |
Embedded XML
The programming language Scala has built-in support for XML. You can create something like this (taken from the Scala overview document):
| Code Block |
|---|
val labPhoneBook =
<phonebook>
<descr>Phone numbers of<b>XML</b> hackers.</descr>
<entry>
<name>Burak</name>
<phone where="work"> +41 21 693 68 67 </phone>
<phone where="mobile"> +41 78 601 54 36 </phone>
</entry>
</phonebook>;
|
Decoupling of static and instance methods
Also taken from the Scala programming language. It doesn't have static methods. All the static methods should be placed in a singleton. Static members are not a part of instance variables, so you shouldn't have to declare them in the same class.
New way of declaring Expando
Could be just like in annonymous types in C#. For example:
| Code Block |
|---|
def foo = new (prop:"value") foo.bar = "bar" |
First Class Support for User-Defined Boolean Types
There is already quite good support for user-defined numeric data (e.g. classes that act like numeric data in expressions) using the current support for operator overloading. But if one needs to define a class that operates in expressions like a Boolean, it can't be done. The following changes would make this possible and these seem consistent with the overall idea and design of Groovy:
- Enable operator overloading for logical AND, logical OR, logical NOT. For logical AND and logical OR, the deferred evaluation of the right operand can be maintained by passing a Closure to the method. The signatures might be something like this:
Code Block Boolean land(Closure) Boolean lor(Closure)
- Enable assignment operator overloading. This is needed to allow a semantic like
Note that overriding the assignment operator makes it significantly easier to replace numeric types too since one can handle cases likeCode Block MyBooleanClass bool = true
which is not possible today.Code Block MyNumericClass num = 10
- Today due to "Groovy Truth" processing, any non-null object reference (that is not a Boolean) will evaluate to true. To enable user-defined Boolean type data, Groovy Truth would need to be modified to optionally "unbox" a non-null object reference into a Boolean value if it has a booleanValue() method. This would allow one to do something like this
In such a case, the bool instance can be either false or true and can be directly used for control flow and other operations that normally expect a Boolean.Code Block MyBooleanType bool = something(); if bool || somethingElse() { ... }
With these changes, user-defined boolean replacement classes would get first-class support in the language.
Smalltalk-like syntax for methods
I've seen that in Groovy 1.5 it was possible to avoid using parenthesis when calling a method. It was made to simplify the reading in a more natural way...
Nevertheless I'm not sure that the goal is today reached... The groovy syntax was primarly settled to make the step from Java easier for java coders...Along the versions, some syntactic sugar was added to fulfill new needs...to reach the point where going from jav to groovy is not so straightforward... Personnaly it is not an issue, but I would like to point out that if we differ more and more from java, why not adopting a syntax which is more accurate and simpler?
Personnaly, I find the Smalltalk syntax simpler and more elegant... I think that we could add some syntactic "tournures" of Smalltalk in Groovy 2.0, especially for defining new methods....
definition example :
| Code Block |
|---|
def print: anObject on: aStream {
....
}
|
or
| Code Block |
|---|
def print: Customer aCustomer on: FileStream aStream {
...
}
|
or better
| Code Block |
|---|
def print: aCustomer as Customer on: aStream as FileStream {
...
}
|
use example :
| Code Block |
|---|
def aCustomer = new Customer(); WriteStream aStream = new FileStream(); print:aCustomer on: aStream ; |
Expect for Groovy
Expect has been already ported to other languages:
Why can't we have it built in?
My proposal:
Automatic constructor for immutable Groovy Beans
Automatically create a constructor for all final properties of a Groovy Bean.
| Code Block |
|---|
class Data {
final Integer id
final String name
}
|
And then:
| Code Block |
|---|
def myData1 = new Data(5, "John") def myData2 = new Data(8, "Jane") |
There should be no setters generated, and not be possible to change the values of id or name after object creation.
It would be even better if you could use named parameters to the constructor as well:
| Code Block |
|---|
def myData1 = new Data(id: 5, name:"John") def myData2 = new Data(name:"Jane", id:8) |