https://github.com/JetBrains/intellij-community
https://github.com/gradle/gradle
https://github.com/apache/groovy
https://github.com/murez-nst/JVM-Based.git and then execute the gradlew build command on your local directory. Finally, create a new Groovy script, Test.I will not discuss the installation and creation steps anymore in this tutorial. For more details, please visit my previous one.
In my previous tutorial, I've already discussed about Groovy DSL can be more flexible and powerful to build such a custom syntax, so anyone can easily interpret the codes even to who doesn't understand the programming at all.
But, I think DSL comes prematurely to the beginners. Because to get closer, they have to understand Closure extensively in advance. And now, this tutorial will explain it in detail. Initially, I will use the term of block to simply refer to the block of statements or algorithm to solve a particular case, i.e. function, method or closure. Because in Groovy, they have the same major characteristic as performing a particular process depends on the parameter(s) (as input), has the type which is a type of the returned value (as output) and always produce any output, at least null or even you somehow define it which does not intend to return any value at all.
The main goal of a block is to prevent redundant definitions. So, if Java SE has provided a solution raising a number to the power of the second one, Math.pow(double, double), then we don't need to create the same new definition. Just use the existing one.
Now, they can be distinguished from each other very easily as follows
The base form of a block that only depends on parameter(s) and the other same level members. The term of function in the world of programming is general and comprehensive meaning, sometimes in a particular language it has a specific meaning. Java was originally intended for object-oriented programming, although it has finally adopted functional programming. So, I think the right definition for a function in the context of Java is the static one which is defined using the static keyword.
class A {
private final NON_STATIC_RESOURCE = 'will never be touched'
static void sayHello(def yourName) { // (1)
new Inner() // (2)
new Callable() { // (3)
@Override
void to(String name) { }
}
println "Hello ${ yourName }!" // (4)
}
class Inner { }
interface Callable {
void to(String name)
}
}
def result = A.sayHello('World')
println result // (5)
static keyword.class A {
...
static def greeting(String salaam) {
new Callable() {
@Override
void to(String name) {
println "$salaam $name!"
}
}
}
}
def sayHello = A.greeting('Hello')
def sayHi = A.greeting('Hi')
sayHello.to 'World'
sayHello.to 'Groovy'
sayHi.to 'Murez'
println "Hello ${ NON_STATIC_RESOURCE }!"null, why?sayHello method with a void type is executed, then a null value will be given.It is the same as a function but can access non-static members. This is why a method is always represented as a behavior on an object.
In the JVM-based context, a function will never access a field (or sometimes as an attribute or property) which is a non-static member. So, it is ridiculous to create an object first and then execute a function. This is why we only have to do A.sayHello('World') in order to execute a function as in the previous example.
While in the object-oriented programming context, a method in any class always depends on the fields to perform such a particular process. So in order to execute a method, we must create the object first.
class B {
private String salaam
void say(String name) {
println "$salaam $name!" // (1)
}
}
def withHello = new B(salaam: 'Hello')
def withHi = new B(salaam: 'Hi')
withHello.say 'World' // (2)
withHi.say 'Murez'
static keyword.say method must be invoked by first creating an object of enclosing class.Eventually why do you have to define a method while there are no dependencies with any property? Then you have to redefine it into a function.
Sometimes, if referring to any name is ambiguous, we can use this keyword explicitly that corresponds to the enclosing class where it is used.
class Outer {
class Inner {
private String desc
void set(String desc) {
this.desc = desc // (1)
}
}
void get() { this.desc } // (2)
}
desc is ambiguous between field or argument. So, this used here corresponds to the Inner class and then this.desc is a property.this used here corresponds to the Outer class while the field of desc never exists in the Outer class finally this statement will cause an errorOf course this cannot be used in a static context, because this only refers to any non-static member.
This is the most powerful one, in addition to parameter(s) it also depends on the undefined members which can be easily resolved using delegation, as long as the delegated object defines the missing members correctly.
In Java, any interface that has only one abstract method can be applied as a lambda expression which is an anonymous method, while closure is a lambda expression plus delegate capability.
Closure is an abstract class, but we can create it in the same way as easy as lambda expression. This is the simplest closure, { } that returns a null. Delegation can be done by simply invoking the setDelegate method as follows,
class Any {
private myName
String getName() { myName } // (1)
}
def say = {
println "$it ${ name }!" // (2)
}
say.delegate = new Any(myName: 'World') // (3)
say 'Hello' // (4)
say.delegate = new Any(myName: 'Murez')
say 'Hi'
This class defines a member which is a method named getName.
Create a closure that will print an argument as it and then join with the other undefined member. If we immediately execute this closure, then an error will occur because the name is completely undefined.
We delegate an object to this closure by passing it a new instance of the Any class and then give a string to the constructor. This technique is called Named argument constructor one of the features provided by Groovy and we'll not discuss it in this tutorial.
There is no error. Because we have delegated an object that has defined a name() method.
But instead of defining the getName() method, should it define the name() one?
Here myName is a property of Any and its getter is getName. Then in Groovy, the getter can be invoked in two ways, as .getName() or just .name.
Even so about the setter, such as a property of the delegate at the closure which can be invoked as .setDelegate(object) or .delegate = object as well.
Closure has a generic which is an abstract type of a value that will be returned by executing a closure. It can be executed like a function in general, but actually the call method is implicitly invoked. Sometimes we have to call him explicitly to avoid ambiguity, like the following example
class C {
static def isPositive = { it > 0 }
static def isPositive(def number) {
throw new UnsupportedOperationException()
}
static def test(def value) {
isPositive(value) // (1)
}
}
println C.test(1)
isPositive.call(value), then it is considered as a closure rather than a function.this and ownerIf a function can't refer to any class member (except the static ones) or we can define it as does not have a lexical scope, then a method has a lexical scope of this which references to an enclosing class. Then closures other than having this also have a lexical scope of owner and delegate.
If this corresponds to an enclosing class, then owner corresponds to the enclosing of either a class or a closure where it is defined. While delegate as we know, it corresponds to the delegated object, so we don't need to discuss about it in more detail.
How could it be?
Yes, Exactly! Because a closure can be defined in another closure while a function or method cannot.
class Outer {
class Inner {
def takeOwner() {
({ getOwner() }) // (1)
}
Closure 'Take a Nested closure'() {
({ // (2)
({ owner })() // (3)
})
}
}
void test() {
def inner = new Inner() // (4)
assert inner.takeOwner()() == inner // (5)
Closure nested = inner.'Take a Nested closure'() // (6)
assert nested() == nested // (7)
assert ({ owner })() == this // (8)
println 'Successful!' // (9)
}
}
new Outer().test()
takeOwner returns a closure which returns an object of the owner.def takeOwner() {
return { getOwner() }
}
So, if you pass a closure as a return value without first storing it to a variable then you have to surround it with parentheses.Closure 'Take a Nested closure'() {
return {
def innerClosure = { owner }
return innerClosure.call()
}
}
Inner classowner's characteristic will be the same as this, which is returning an instance of enclosing class, i.e. Inner.def closure = inner.takeOwner()
assert closure() == inner
owner. Because owner is executed in the context of an inner closure then it returns an instance of enclosing closure which is the outer one.Outer class context, it will automatically become this and return an instance of Outer class.I will express my gratitude in a different way,
https://github.com/murez-nst/JVM-Based/tree/master/Groovy/Lombok