"When you've found the treasure, stop digging!"
I'm wanting to use more functional programming in Groovy, and thought rewriting the following method would be good training. It's harder than it looks because Groovy doesn't appear to build short-circuiting into its more functional features.
Here's an imperative function to do the job:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
String shortestUniqueName(String nameToShorten) {
def currentLevel = 1
String shortName = ''
def separator = '/'
while (fullyQualifiedNames.findAll { fqName ->
shortName = nameToShorten.tokenize(separator)[-currentLevel..-1].join(separator)
fqName.endsWith(shortName)
}.size() > 1) {
++currentLevel
}
return shortName
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
It scans a list of fully-qualified filenames and returns the shortest unique form. There are potentially hundreds of fully-qualified names.
As soon as the method finds a short name with only one match, that short name is the right answer, and the iteration can stop. There's no need to scan the rest of the name or do any more expensive list searches.
But turning to a more functional flow in Groovy, neither return nor break can drop you out of the iteration:
return simply returns from the present iteration, not from the whole .each so it doesn't short-circuit.
break isn't allowed outside of a loop, and .each {} and .eachWithIndex {} are not considered loop constructs.
I can't use .find() instead of .findAll() because my program logic requires that I scan all elements of the list, nut just stop at the first.
There are plenty of reasons not to use try..catch blocks, but the best I've read is from here:
Exceptions are basically non-local goto statements with all the
consequences of the latter. Using exceptions for flow control
violates the principle of least astonishment, make programs hard to read
(remember that programs are written for programmers first).
Some of the usual ways around this problem are detailed here including a solution based on a new flavour of .each. This is the closest to a solution I've found so far, but I need to use .eachWithIndex() for my use case (in progress.)
Here's my own poor attempt at a short-circuiting functional solution:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
def shortestUniqueName(String nameToShorten) {
def found = ''
def final separator = '/'
def nameComponents = nameToShorten.tokenize(separator).reverse()
nameComponents.eachWithIndex { String _, int i ->
if (!found) {
def candidate = nameComponents[0..i].reverse().join(separator)
def matches = fullyQualifiedNames.findAll { String fqName ->
fqName.endsWith candidate
}
if (matches.size() == 1) {
found = candidate
}
}
}
return found
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
Please shoot me down if there is a more idiomatic way to short-circuit in Groovy that I haven't thought of. Thank you!
There's probably a cleaner looking (and easier to read) solution, but you can do this sort of thing:
String shortestUniqueName(String nameToShorten) {
// Split the name to shorten, and make a list of all sequential combinations of elements
nameToShorten.split('/').reverse().inject([]) { agg, l ->
if(agg) agg + [agg[-1] + l] else agg << [l]
}
// Starting with the smallest element
.find { elements ->
fullyQualifiedNames.findAll { name ->
name.endsWith(elements.reverse().join('/'))
}.size() == 1
}
?.reverse()
?.join('/')
?: ''
}
Related
I want to check if the result from a request is having any issue. I categorize it into two: i) server error, ii) something else that is not a success. The third category is, result actually being a success. However, in the third category, I don't want to do anything.
So, my desirable code is:
if res.status().is_server_error() {
panic!("server error!");
} else if !(res.status.is_success()){
panic!("Something else happened. Status: {:?}", res.status());
} else{
pass;
}
I am aware of other ways to achieve this result: using match, ifs instead of if else if. But I wanted to learn what is the corresponding keyword of pass, like we have in Python. My aim is: if result is successful, just move along, if not, there are two ways to handle that panic.
Behold!
if predicate {
do_things();
} else {
// pass
}
Or even better
if predicate {
do_things();
} // pass
Or as I’ve recently taken to calling it the implicit + pass system
if predicate {
do_things();
}
In all seriousness there is no pass and no need for a pass in rust. As for why it exists in python, check out this answer
Python needs pass because it uses indentation-based blocks, so it requires some syntax to "do nothing". For example, this would be a syntax error in a Python program:
# syntax error - function definition cannot be empty
def ignore(_doc):
# do nothing
count = process_docs(docs, ignore) # just count the docs
The ignore function has to contain a block, which in turn must contain at least one statement. We could insert a dummy statement like None, but Python provides pass which compiles to nothing and signals the intention (to do nothing) to the human reader.
This is not needed in Rust because Rust uses braces for blocks, so one can always create an empty block simply using {}:
// no error - empty blocks are fine
fn ignore(_doc: &Document) {
// do nothing
}
let count = process_docs(docs, ignore); // just count the docs
Of course, in both idiomatic Python and Rust, one would use a closure for something as simple as the above ignore function, but there are still situations where pass and empty blocks are genuinely useful.
I need to create a string from a array of map in groovy.
Required string = ^(123|456|789)
At present I am doing something like below, will this cause performance issue in production box or should I use StringBuffer java class?
def getProjectList(def caseResult) {
def projectList = ""
caseResult.each { projno ->
if (projectList.length() == 0) {
projectList = "^(${projno.project_no}|"
} else {
if (projectList.indexOf(projno.project_no) == -1)
projectList+="${projno.project_no}|"
}
}
projectList = projectList.substring(0, projectList.length() - 1)
projectList += ')'
return projectList
}
I'd go for ease of reading...
def getProjectList(def caseResult) {
"^(${caseResult.project_no.join('|')})"
}
Actually, you just want the unique ones don't you?
def getProjectList(def caseResult) {
"^(${caseResult.project_no.unique().join('|')})"
}
I need to create a string from a array of map in groovy.
It would be extremely useful to define parameter type then.
The return type too.
will this cause performance issue in production box
Well, define performance issue first. Have you measured anything to think your code has any performance issues? If not, it looks like a typical "premature optimization"
should I use StringBuffer java class
If you worry about performance, then you should rather use StringBuilder, as StringBuffer is thread-safe, taking a little performance hit.
If your code suffers from anything, it's rather readability than performance.
And I recommend you this StackExchange site, dedicated to such questions - https://codereview.stackexchange.com/ - give it a try!
My current work project allows user-provided expressions to be evaluated in specific contexts, as a way for them to extend and influence the workflow. These expressions the usual logical ones f. To make it a bit palatable for non-programmers, I'd like to give them the option of using literal operators (e.g. and, or, not instead of &, |, !).
A simple search & replace is not sufficient, as the data might contains those words within quotes and building a parser, while doable, may not be the most elegant and efficient solution.
To make the question clear: is there a way in Groovy to allow the users to write
x > 10 and y = 20 or not z
but have Groovy evaluate it as if it were:
x > 10 && y == 20 || !z
Thank you.
Recent versions of Groovy support Command chains, so it's indeed possible to write this:
compute x > 10 and y == 20 or not(z)
The word "compute" here is arbitrary, but it cannot be omitted, because it's the first "verb" in the command chain. Everything that follows alternates between verb and noun:
compute x > 10 and y == 20 or not(z)
───┬─── ──┬─── ─┬─ ───┬─── ─┬─ ──┬───
verb noun verb noun verb noun
A command chain is compiled like this:
verb(noun).verb(noun).verb(noun)...
so the example above is compiled to:
compute(x > 10).and(y == 20).or(not(z))
There are many ways to implement this. Here is just a quick & dirty proof of concept, that doesn't implement operator precedence, among other things:
class Compute {
private value
Compute(boolean v) { value = v }
def or (boolean w) { value = value || w; this }
def and(boolean w) { value = value && w; this }
String toString() { value }
}
def compute(v) { new Compute(v) }
def not(boolean v) { !v }
You can use command chains by themselves (as top-level statements) or to the right-hand side of an assignment operator (local variable or property assignment), but not inside other expressions.
If you can swap operators like > and = for the facelets-like gt and eq, respectively, i THINK your case may be doable, though it will require a lot of effort:
x gt 10 and y eq 20 or not z
resolves to:
x(gt).10(and).y(eq).20(or).not(z)
And this will be hell to parse.
The way #Brian Henry suggested is the easiest way, though not user-friendly, since it needs the parens and dots.
Well, considering we can swap the operators, you could try to intercept the Integer.call to start expressions. Having the missing properties in a script being resolved to operations can solve your new keywords problem. Then you can build expressions and save them to a list, executing them in the end of the script. It's not finished, but i came along with this:
// the operators that can be used in the script
enum Operation { eq, and, gt, not }
// every unresolved variable here will try to be resolved as an Operation
def propertyMissing(String property) { Operation.find { it.name() == property} }
// a class to contain what should be executed in the end of the script
#groovy.transform.ToString
class Instruction { def left; Operation operation; def right }
// a class to handle the next allowed tokens
class Expression {
Closure handler; Instruction instruction
def methodMissing(String method, args) {
println "method=$method, args=$args"
handler method, args
}
}
// a list to contain the instructions that will need to be parsed
def instructions = []
// the start of the whole mess: an integer will get this called
Integer.metaClass {
call = { Operation op ->
instruction = new Instruction(operation: op, left: delegate)
instructions << instruction
new Expression(
instruction: instruction,
handler:{ String method, args ->
instruction.right = method.toInteger()
println instructions
this
})
}
}
x = 12
y = 19
z = false
x gt 10 and y eq 20 or not z
Which will give an exception, due the not() part not being implemented, but it can build two Instruction objects before failing:
[Instruction(12, gt, 10), Instruction(19, eq, 20)]
Not sure if it is worth it.
The GDK tacks on and() and or() methods to Boolean. If you supplied a method like
Boolean not(Boolean b) {return !b}
you could write something like
(x > 10).and(y == 20).or(not(4 == 1))
I'm not sure that's particularly easy to write, though.
I have a closure to find all files with name matching a pattern and containing a given String:
def path = "path/to/logs"
def namePatten = ~/.*.log/
def contentPattern ~/.*ERROR.*/
def result = []
new File(path).eachDirRecurse { File dir ->
dir.eachFileMatch(namePattern) { File f ->
f.eachLine { String l ->
if(l.matches(contentPattern)) {
result.add(f)
return
}
}
}
But I'm pretty sure I can have something shorter (hey, else I can use plain java :) )
I have tried to find a way to write this a bit like that:
result = new File(path).eachFileRecurse.filter(filePattern).grep(contentPattern)
as I would have done using guava or similar fluent interface collection tools.
How woud you write this closure in a concise, yet still readable, manner ?
The smallest I can get it to at present is to use the File.traverse method to recursively scan the root folder:
new File( path ).traverse( nameFilter: namePattern ) { f ->
if( f.filterLine( { it ==~ contentPattern } ) as String ) result << f
}
Using filterLine returns a Writable which I convert to a String as then we can exploit the Groovy truth to see whether to add the file to result or not.
Edit:
You can also use AntBuilder to do a similar thing:
def result = new AntBuilder().fileset( dir:'path/to/logs', includes:'**/*.log' ) {
containsregexp expression:'.*ERROR.*'
}*.file
Which I tend to prefer as it generates the list in one go, rather than adding results to an already defined results list.
is there a way to 'break' out of a groovy closure.
maybe something like this:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
I often forget that Groovy implements an "any" method.
[1, 2, 3].any
{
println it
return (it == 2)
}
12/05/2013 Heavily Edited.
Answering the question that was asked.
Is it possible to break out of a Closure?
You would "break" out of a closure by issuing the return keyword. However that isn't helpful in the example that is given. The reason for this is that the closure (think of it as a method) is called by the each method for every item in the collection.
If you run this example you will see it will print 1 then 3.
[1, 2, 3].each {
if (it == 2) return
println(it)
}
Why break in the context of each doesn't make sense.
To understand why you cannot break out of the each method like you could break out of a for loop you need to understand a bit of what is actually happening. Here is a gross simplification what the each method on a collection does.
myEach([0,1,3])
void myEach(List things) {
for (i in things) {
myEachMethod(i)
}
}
void myEachMethod(Object it) { // this is your Closure
if(it == 2) return
println it
}
As you can see the closure is basically a method that can be passed around. Just as in java you cannot break from within method call or closure.
What to do instead of breaking from each.
In Groovy you are supposed to express your code using high level abstractions as such primitive looping is not idiomatic. For the example that you gave I would consider making use of findAll. For example:
[1,2,3].findAll { it < 2 }.each { println it }
I hope this helps you understand what is going on.
Answering the implied question.
Can you break out of the Collection.each iterations against your supplied closure?
You cannot break out of the each method without throwing and catching an exception as John Wagenleitner has said. Although I would argue that throwing and catching an exception in the name of flow control is a code smell and a fellow programmer might slap your hands.
You can throw an exception:
try {
[1, 2, 3].each {
println(it)
if (it == 2)
throw new Exception("return from closure")
}
} catch (Exception e) { }
Use could also use "findAll" or "grep" to filter out your list and then use "each".
[1, 2, 3].findAll{ it < 3 }.each{ println it }
Take a look at Best pattern for simulating continue in groovy closure for an extensive discussion.
Try to use any instead of each
def list = [1, 2, 3, 4, 5, -1, -2]
list.any { element ->
if (element > 3)
return true // break
println element
}
The result : 1, 2, 3
Just using special Closure
// declare and implement:
def eachWithBreak = { list, Closure c ->
boolean bBreak = false
list.each() { it ->
if (bBreak) return
bBreak = c(it)
}
}
def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
if (it > 3) return true // break 'eachWithBreak'
println it
return false // next it
}
There is an other solution. Although, that groovy stuff like each/find/any is quite cool: if it doesn't fit, don't use it. You can still use the plain old
for (def element : list)
Especially, if you want to leave the method, too. Now you are free to use continue/break/return as you like. The resulting code might not be cool, but it is easy and understandable.
This is in support of John Wagenleiter's answer. Tigerizzy's answer is plain wrong. It can easily be disproved practically by executing his first code sample, or theoretically by reading Groovy documentation. A return returns a value (or null without an argument) from the current iteration, but does not stop the iteration. In a closure it behaves rather like continue.
You won't be able to use inject without understanding this.
There is no way to 'break the loop' except by throwing an exception. Using exceptions for this purpose is considered smelly. So, just as Wagenleiter suggests, the best practice is to filter out the elements you want to iterate over before launching each or one of its cousins.
With rx-java you can transform an iterable in to an observable.
Then you can replace continue with a filter and break with takeWhile
Here is an example:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}