I understand that the gradle DSL
task doTask { logger.info "some text" }
will actually call the method task(String,Closure) on the Project delegate object. It's more or less a short hand for
task("doTaks", {logger.info("some text")})
That's all fine. But things get complicated when I try to understand some gradle DSL syntax I've seen in third party build scripts:
task doTask (dependsOn: 'otherTask'){logger.info "some text"}
I figure that groovy will create a map from (dependsOn: 'otherTask'), and that somehow the Project method
task(Map args, String name, Closure config)
will be called. But how do these additional parentheses come into play, why are they necessary, how does groovy figure out what we want here? The syntax looks totally counter-intuitive to me with my minimal groovy skill. I would never guess that I have to do it this way to make it work.
So, that's the question: how does groovy figure out what to do with this command:
task doTask (dependsOn: 'otherTask'){ // some code }
You can invoke groovy methods using one the following syntaxes:
Args must be all comma separated within parenthesis:
method(arg1, arg2, ..., argN, argClosure)
Args must be all comma separated without parenthesis:
method arg1, arg2, ..., argN, argClosure
If the last argument is a closure, all previous args must be all comma separated within parenthesis, and the code block (within braces {...}) following the closing parenthesis will be interpreted as the last Closure argument argClosure:
method(arg1, arg2, ..., argN) { ... }
If you DO NOT want the code block within the curly braces to be interpreted as a Closure argument for the preceding method invocation; then end the method invocation with a semicolon:
// Because of `;` following { ... } is not a Closure argument for `method`
method(arg1, arg2, ..., argN); { ... }
A method that accepts as an argument a single Map or a Map and a closure, may be invoked using the named parameters syntax; which will transform each named argument into an entry in the map and the last argument will be a closure. This will create the following intuitive syntactic variants:
method(name1: arg1, name2: arg2, ..., nameN: argN, argClosure)
method name1: arg1, name2: arg2, ..., nameN: argN, argClosure
method(name1: arg1, name2: arg2, ..., nameN: argN) { ... }
Groovy provides tons of syntactic sugar, so other intuitive variants can be found around this; but this gives you the feeling for groovy's way of handling Closure arguments.
The following is a working demo of these different ways of doing a method invocation:
import java.time.LocalDateTime
def handleWithClosure(data1, data2, closure) {
closure("$data1. $data2")
}
def logger = { println "${LocalDateTime.now()} - $it" }
handleWithClosure(1, 'All within parenthesis', logger)
handleWithClosure 2, 'All without parenthesis', logger
handleWithClosure(3, 'List of arguments within parenthesis and closure outside') { logger(it) }
def handleMapWithClosure(map, closure) {
handleWithClosure(map['num'], "[Named Arguments/Map based] ${map['msg']}", closure)
}
handleMapWithClosure(msg: 'All within parenthesis', num: 1, logger)
handleMapWithClosure msg: 'All without parenthesis', num: 2, logger
handleMapWithClosure(msg: 'List of arguments within parenthesis and closure outside', num: 3) { logger(it) }
Running it you can see how it is treating all these syntactic options.
Complete code on GitHub
Hope this helps.
Related
an interesting behaviour in the Scala compiler, prepared queries that use the “IN” operator will require special binding at compile time, called ListValue.
trait InSelectPreparedExamples extends db.Connector {
lazy val selectInExample = db.entries.select.where(_.car in ?).prepareAsync()
// This is a select * query, selecting the entire record
def selectFromList(values: List[UUID]): Future[List[CarMetric]] = {
selectInExample.flatMap(_.bind(ListValue(values)).fetch)
}
// We can use also use a vargargs style method call to achieve the same goal.
def selectFromArgs(args: UUID*): Future[List[CarMetric]] = {
selectInExample.flatMap(_.bind(ListValue(args: _*)).fetch)
}
}
when i use this ListValue i have got warn
**
warn] or remove the empty argument list from its definition (Java-defined methods are exempt).
[warn] In Scala 3, an unapplied method like this will be eta-expanded into a function.
[warn] selectInExample.flatMap(_.bind(ListValue(values)).fetch())
[warn] ^
scalaVersion := "2.13.4"
libraryDependencies += "com.outworkers" %% "phantom-dsl" % "2.59.0"
how can fix it ?
In Scala 2.12 and below the following syntax was valid without any warnings
def test(): A = ???
test // is automatically expanded to test()
However from Scala 2.13 this gives a warning
Auto-application to `()` is deprecated. Supply the empty argument list `()` explicitly to invoke method test
And in Scala 3 that syntax would be illegal.
In your case the phantom-dsl library has a class with methods with empty parameter list - https://github.com/outworkers/phantom/blob/v2.59.0/phantom-dsl/src/main/scala/com/outworkers/phantom/builder/primitives/Primitives.scala#L166
once they fix the bug you already reported the warnings should be gone.
Below you can see a trailing lambda syntax:
runApplication</*... */>(/*... */) {
setBannerMode(/*... */)
}
I understand the idea that we can pass a lambda outside the parens as a last argument. But what does the code above actually do? setBannerMode is a method that is going to override the one in the parent class, isn't it? If yes, what class is the parent one? Is there some this context between the braces of the trailing lambda? In general, what's happening there?
the code is from here
setBannerMode is a method that is being overriden, isn't it?
No. What you are doing is passing a lambda to runApplication() that has a this implicit receiver .
Here is the definition (Spring documentation):
inline fun <reified T : Any> runApplication(vararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext =
SpringApplication(T::class.java).apply(init).run(*args)
The init: SpringApplication.() -> Unit here is the definition of the lambda with implicit receiver. It means that inside the lambda, this will be a SpringApplication.
To break it down:
SpringApplication(T::class.java) - create a new spring application. T is calculated from the calling context by the Kotlin compiler (that's what reified T means).
apply(init). Calls your lambda (init), with the SpringApplication as the receiver (Kotlin docs for apply).
Call the SpringApplication's run() function with the varargs arguments. This function returns a ConfigurableApplicationContext.
So, you are calling the setBannerMode() method of the instantiated SpringApplication object.
I'm learning Dart and see the following idiom a lot:
someFuture.then((_) => someFunc());
I have also seen code like:
someOtherFuture.then(() => someOtherFunc());
Is there a functional difference between these two examples?
A.k.a., What does passing _ as a parameter to a Dart function do?
This is particularly confusing given Dart's use of _ as a prefix for declaring private functions.
It's a variable named _ typically because you plan to not use it and throw it away. For example you can use the name x or foo instead.
The difference between (_) and () is simple in that one function takes an argument and the other doesn't.
DON’T use a leading underscore for identifiers that aren’t private.
Exception: An unused parameter can be named _, __, ___, etc. This
happens in things like callbacks where you are passed a value but you
don’t need to use it. Giving it a name that consists solely of
underscores is the idiomatic way to indicate the value isn’t used.
https://dart.dev/guides/language/effective-dart/style
An underscore (_) is usually an indication that you will not be using this parameter within the block. This is just a neat way to write code.
Let's say I've a method with two parameters useful and useless and I'm not using useless in the code block:
void method(int useful, int useless) {
print(useful);
}
Since useless variable won't be used, I should rather write the above code as:
void method(int useful, int _) { // 'useless' is replaced with '_'
print(useful);
}
From the Dart Doc - PREFER using _, __, etc. for unused callback parameters.
Sometimes the type signature of a callback function requires a
parameter, but the callback implementation doesn't use the
parameter. In this case, it's idiomatic to name the unused parameter
_. If the function has multiple unused parameters, use additional
underscores to avoid name collisions: __, ___, etc.
futureOfVoid.then((_) {
print('Operation complete.');
});
This guideline is only for functions that are both anonymous and
local. These functions are usually used immediately in a context
where it's clear what the unused parameter represents. In contrast,
top-level functions and method declarations don't have that context,
so their parameters must be named so that it's clear what each
parameter is for, even if it isn't used.
Copy paste the following code in DartPad and hit Run -
void main() {
Future.delayed(Duration(seconds: 1), () {
print("No argument Anonymous function");
});
funcReturnsInteger().then((_) {
print("Single argument Anonymous function " +
"stating not interested in using argument " +
"but can be accessed like this -> $_");
});
}
Future<int> funcReturnsInteger() async {
return 100;
}
That expression is similar to "callbacks" in node.js, the expression have relation to async task.
First remember that => expr expression is shorthand for {return *expr*}, now in someFuture.then((_) => someFunc()), someFuture is a variable of type Future, and this keeps your async task, with the .then method you tell what to do with your async task (once completed), and args in this method you put the callback ((response) => doSomethingWith(response)).
You learn more at Future-Based APIs and Functions in Dart. Thanks
Very common use, is when we need to push a new route with Navigator but the context variable in the builder is not going to be used:
// context is going to be used
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewPage(),
));
// context is NOT going to be used
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => NewPage(),
));
I think what people are confusing here is that many think the _ in
someFuture.then((_) => someFunc());
is a parameter provided to the callback function which is wrong, its actually a parameter passed back from the function that you can give a name that you want (except reserved keywords of course), in this case its an underscore to show that the parameter will not be used. otherwise, you could do something like in example given above:((response) => doSomethingWith(response))
I'm new to groovy and I'm wondering where can I find a full list of predefined
groovy variables like it and delegate?
The particular thing that I'm interested in is if there are predefined keyword for
the reference to the object from where the current method was invoked, for example:
5.times { print 5 - it}
with the use of such keyword it should be something like:
5.times { print *keyword* - it }
so the question is what's the keyword should be used there?
P.S.: another example:
MyObject myObject = new myObject();
myObject.getField(); // MyObject has method named getField
myObject.doJob ({
...
((MyObject)*keyword*).getField(); // instead of myObject.getField();
...
})
For a good list of all actual keywords (which are fewer than you'd think) and object-level properties that are like keywords, this article is really good: http://marxsoftware.blogspot.com/2011/09/groovys-special-words.html
If you have control over the doJob method in your example, then you should set the delegate of the closure:
def doJob(Closure closure) {
closure.delegate = this
closure.resolveStrategy = Closure.DELEGATE_FIRST
// loop or whatever
closure()
}
Now, in your closure, you can reference any properties on the parent object directly, like so:
myObject.doJob ({
...
getField()
...
})
Groovy Closures - Implicit Variables.
Are you asking for this?
int number = 5
number.times { print number - it }
Hope this will help you
(Note: I'm using Scala 2.7.7 here, not 2.8).
I'm doing something pretty simple -- creating a map based on the values in a simple, 2-column CSV file -- and I've completed it easily enough, but I'm perplexed at why my first attempt didn't compile. Here's the code:
// Returns Iterator[String]
private def getLines = Source.fromFile(csvFilePath).getLines
// This doesn't compile:
def mapping: Map[String,String] = {
Map(getLines map { line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}.toList:_*)
}
// This DOES compile
def mapping: Map[String,String] = {
def strPair(line: String): (String,String) = {
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}
Map(getLines.map( strPair(_) ).toList:_*)
}
The compiler error is
CsvReader.scala:16:
error: value toList is not a member of
(St ring) => (java.lang.String,
java.lang.String) [scalac] possible
cause: maybe a semicolon is missing
before `value toList'? [scalac]
}.toList:_*) [scalac] ^
[scalac] one error found
So what gives? They seem like they should be equivalent to me, apart from the explicit function definition (vs. anonymous in the nonworking example) and () vs. {}. If I replace the curly braces with parentheses in the nonworking example, the error is "';' expected, but 'val' found." But if I remove the local variable definition and split the string twice AND use parens instead of curly braces, it compiles. Can someone explain this difference to me, preferably with a link to Scala docs explaining the difference between parens and curly braces when used to surround method arguments?
Looks like the difference is because you are using the operator notation in the first example. If you add an extra set of parentheses it works:
def mapping: Map[String,String] = {
Map((getLines map { line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}).toList:_*)
}
or if you don't use the operator syntax it works
def mapping: Map[String,String] = {
Map(getLines.map({ line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}).toList:_*)
}
I think the problem is that using the normal method invocation syntax has higher precedence than the operator syntax for method calls. This meant that the .toList was being applied to the anonymous function rather than to the result of the map method call.
If you don't use operator syntax, it compiles fine:
//Compiles
def mapping: Map[String,String] = {
Map(getLines.map { line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}.toList:_*)
}
There is not a problem with how you use the anonymous function, but as Ben mentioned, the syntax of calls map without the . is not equivalent to the typical Java-style method call.