I've noticed that I can't shadow variables in closures. For example, in a function:
x = [1, 2, 3]
def foo() {
def item = 'whatever'
x.findAll{ item -> item > 1 }
}
foo()
// org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
// /private/tmp/foo.groovy: 4: The current scope already contains a variable of the name item
// # line 4, column 14.
// x.findAll{ item -> item > 1 }
// ^
This is a problem for me, because I want to define a DSL with closures, which implicitly define it and surprise my users:
def callClosure(body) {
body()
}
x = [1, 2, 3]
callClosure { x.findAll{ it -> it > 1 } } // same error
Is it possible to define closures with variables, even if they might shadow the enclosing scope?
I've tried this:
callClosure { x.findAll{ def it -> it > 1 } }
callClosure { x.findAll{ final it -> it > 1 } }
but both produce the same error.
Can I declare parameters in my closures such that I don't need to worry about them being defined in parent scopes?
Related
My Problem
Consider a nested object:
> { a: { b: { c: 3 } } }
{ a: { b: { c: 3 } } }
Accessing an inner property with a dot notation for fixed values is done using a dot notation:
> x.a.b.c
3
I would like to access an arbitrary property depending on some condition, for example, instead of accessing b I would like to access the property who's name is stored in the SOME_VARIABLE variable:
> x.a.{SOME_VARIABLE}.c
3
What have I tried
STFW. Probably don't know the exact terminology.
My question
How can I refer to an object property dynamically, with a property name defined in a variable?
There are multiple ways to access an object one of them being [] instead of dots if a object is var object = { inside : '1' } you can access it like this object['inside']. Remember to pass quotes inside if it's static and if it's dynamic pass the variable
I've added an example below
var a = { b: { c: 1 } };
var d = 'b';
console.log(a[d]['c']);
You might also consider using a library like lodash which provides functions to "reach inside" a complex object and return a value, of if the path doesn't exist, a default value.
Example:
const _ = require('lodash')
const target = {
foo: {
bar: {
baz: [1, 2, 3]
}
}
}
console.log(_.get(target, 'foo.bar.baz.1')) // ==> 2
console.log(_.get(target, 'foo.3.bar', 'DEFAULT')) // ==> DEFAULT
if (_.has(target, 'foo.bar')) {
// do something interesting
}
const newKey = 'blorg'
_.put(target, `foo.bar.${newKey}`, 'hello?')
/*
target is now {
foo: {
bar: {
baz: [1, 2, 3]
},
blorg: 'hello?'
}
}
*/
I started learning Groovy, and understood that parentheses are optional in method calls, so
def list = [0, 1, 2, 3]
list.each ({ item ->
println "Item: $item"
})
is the same as
def list = [0, 1, 2, 3]
list.each { item ->
println "Item: $item"
}
But now found this example
def list = [0, 1, 2, 3]
list.each() { item ->
println "Item: $item"
}
which also works. How is it possible to first call method with empty parameter list, and then specify closure after it?
Things are a little different when closures are involved. There is a special facility for closures that occur as the last parameter (as explained here).
As another illustration, consider:
class Foo {
int bar(s, c) {
return c(s)
}
int abc(c, s) {
return c(s)
}
}
def foo = new Foo()
def s = "fox"
This is a classic style:
assert 3 == foo.bar(s, { it.size() })
Yet this will work for closures as last argument:
assert 3 == foo.bar(s) { it.size() }
This is classic:
assert 3 == foo.abc({ it.size() }, s)
But this won't work
// assert 3 == foo.abc({ it.size() }) s
No doubt the reasoning is that if there is only one parameter, as with List.each(), then the syntax is very elegant:
list.each { item -> println item }
I need to get the "calling" list size in a Groovy list closure, e.g.:
def foo = [1,2,3,4,5]
def bar = foo.findAll {
someCondition(it)
}.collect {
processElement(it, <self>.size())
}
where <self> is the list resulting from filtering foo with findAll.
Of course, one can save the intermediate result and get its size, but is it possible to do without it?
The best I can currently think of is:
def bar = foo.findAll { someCondition(it) }
.with { list ->
list.collect { processElement(it, list.size()) }
}
But this just uses with instead of an intermediate result.
Or, you could use the delegate of a Closure:
def foo = [1,2,3,4,5]
def collector = { it -> processElement(it, delegate.size()) }
(collector.delegate = foo.findAll { someCondition(it) }).collect collector
But this is just using the delegate as an intermediate result ;-)
How can I deep copy a map of maps in Groovy? The map keys are Strings or Ints. The values are Strings, Primitive Objects or other maps, in a recursive way.
An easy way is this:
// standard deep copy implementation
def deepcopy(orig) {
bos = new ByteArrayOutputStream()
oos = new ObjectOutputStream(bos)
oos.writeObject(orig); oos.flush()
bin = new ByteArrayInputStream(bos.toByteArray())
ois = new ObjectInputStream(bin)
return ois.readObject()
}
To go about deep copying each member in a class, the newInstance() exists for Class objects. For example,
foo = ["foo": 1, "bar": 2]
bar = foo.getClass().newInstance(foo)
foo["foo"] = 3
assert(bar["foo"] == 1)
assert(foo["foo"] == 3)
See http://groovy-lang.org/gdk.html and navigate to java.lang, Class, and finally the newInstance method overloads.
UPDATE:
The example I have above is ultimately an example of a shallow copy, but what I really meant was that in general, you almost always have to define your own reliable deep copy logic, with perhaps using the newInstance() method, if the clone() method is not enough. Here's several ways how to go about that:
import groovy.transform.Canonical
import groovy.transform.AutoClone
import static groovy.transform.AutoCloneStyle.*
// in #AutoClone, generally the semantics are
// 1. clone() is called if property implements Cloneable else,
// 2. initialize property with assignment, IOW copy by reference
//
// #AutoClone default is to call super.clone() then clone() on each property.
//
// #AutoClone(style=COPY_CONSTRUCTOR) which will call the copy ctor in a
// clone() method. Use if you have final members.
//
// #AutoClone(style=SIMPLE) will call no arg ctor then set the properties
//
// #AutoClone(style=SERIALIZATION) class must implement Serializable or
// Externalizable. Fields cannot be final. Immutable classes are cloned.
// Generally slower.
//
// if you need reliable deep copying, define your own clone() method
def assert_diffs(a, b) {
assert a == b // equal objects
assert ! a.is(b) // not the same reference/identity
assert ! a.s.is(b.s) // String deep copy
assert ! a.i.is(b.i) // Integer deep copy
assert ! a.l.is(b.l) // non-identical list member
assert ! a.l[0].is(b.l[0]) // list element deep copy
assert ! a.m.is(b.m) // non-identical map member
assert ! a.m['mu'].is(b.m['mu']) // map element deep copy
}
// deep copy using serialization with #AutoClone
#Canonical
#AutoClone(style=SERIALIZATION)
class Bar implements Serializable {
String s
Integer i
def l = []
def m = [:]
// if you need special serialization/deserialization logic override
// writeObject() and/or readObject() in class implementing Serializable:
//
// private void writeObject(ObjectOutputStream oos) throws IOException {
// oos.writeObject(s)
// oos.writeObject(i)
// oos.writeObject(l)
// oos.writeObject(m)
// }
//
// private void readObject(ObjectInputStream ois)
// throws IOException, ClassNotFoundException {
// s = ois.readObject()
// i = ois.readObject()
// l = ois.readObject()
// m = ois.readObject()
// }
}
// deep copy by using default #AutoClone semantics and overriding
// clone() method
#Canonical
#AutoClone
class Baz {
String s
Integer i
def l = []
def m = [:]
def clone() {
def cp = super.clone()
cp.s = s.class.newInstance(s)
cp.i = i.class.newInstance(i)
cp.l = cp.l.collect { it.getClass().newInstance(it) }
cp.m = cp.m.collectEntries { k, v ->
[k.getClass().newInstance(k), v.getClass().newInstance(v)]
}
cp
}
}
// assert differences
def a = new Bar("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
def b = a.clone()
assert_diffs(a, b)
a = new Baz("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
b = a.clone()
assert_diffs(a, b)
I used #Canonical for the equals() method and tuple ctor. See groovy doc Chapter 3.4.2, Code Generation Transformations.
Another way to go about deep copying is using mixins. Let's say you wanted an existing class to have deep copy functionality:
class LinkedHashMapDeepCopy {
def deep_copy() {
collectEntries { k, v ->
[k.getClass().newInstance(k), v.getClass().newInstance(v)]
}
}
}
class ArrayListDeepCopy {
def deep_copy() {
collect { it.getClass().newInstance(it) }
}
}
LinkedHashMap.mixin(LinkedHashMapDeepCopy)
ArrayList.mixin(ArrayListDeepCopy)
def foo = [foo: 1, bar: 2]
def bar = foo.deep_copy()
assert foo == bar
assert ! foo.is(bar)
assert ! foo['foo'].is(bar['foo'])
foo = ['foo', 'bar']
bar = foo.deep_copy()
assert foo == bar
assert ! foo.is(bar)
assert ! foo[0].is(bar[0])
Or categories (again see the groovy doc) if you wanted deep copying semantics based on some sort of runtime context:
import groovy.lang.Category
#Category(ArrayList)
class ArrayListDeepCopy {
def clone() {
collect { it.getClass().newInstance(it) }
}
}
use(ArrayListDeepCopy) {
def foo = ['foo', 'bar']
def bar = foo.clone()
assert foo == bar
assert ! foo.is(bar)
assert ! foo[0].is(bar[0]) // deep copying semantics
}
def foo = ['foo', 'bar']
def bar = foo.clone()
assert foo == bar
assert ! foo.is(bar)
assert foo[0].is(bar[0]) // back to shallow clone
For Json (LazyMap) this wokred for me
copyOfMap = new HashMap<>()
originalMap.each { k, v -> copyOfMap.put(k, v) }
copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(copyOfMap))
EDIT: Simplification by: Ed Randall
copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(originalMap))
I've just hit this issue as well, and I just found:
deepCopy = evaluate(original.inspect())
Although I've been coding in Groovy for less than 12 hours, I wonder if there might be some trust issues with using evaluate. Also, the above doesn't handle backslashes. This:
deepCopy = evaluate(original.inspect().replace('\\','\\\\'))
does.
I am afraid you have to do it the clone way. You could give Apache Commons Lang SerializationUtils a try
Given:
class FruitBasket {
int apples = 0
int oranges = 0
}
I need to pick out apples from each FruitBasket. The work need to be done in processFruit:
def processFruit(list, picker) {
list.each {
println "processing " + picker(it)
}
}
def processAll() {
List fruitList = [
new FruitBasket("apples": 2, "oranges": 4),
new FruitBasket("apples": 3, "oranges": 5)
]
processFruit(fruitList, applePicker)
}
def applePicker(FruitBasket f) {
return f.getApples()
}
but it is complaining # runtime that
No such property: applePicker for class: FooTest
possibly a problem with the closures FruitBasket arg...
In that code, applePicker is a method, not a closure.
You can either use a method handle to pass the method as a parameter like so:
processFruit(fruitList, this.&applePicker)
Or change it to an actual closure:
def applePicker = { FruitBasket f -> return f.getApples() }
You are passing applePicker to processFruit, but it is a method. You can only pass closures this way. Redefine applePicker as a closure like so:
applePicker = { FruitBasket f ->
return f.getApples()
}
Or convert the method to a closure when processFruit is called:
processFruit(fruitList, this.&applePicker)