• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Groovy Puzzler

 
Clifton Craig
Ranch Hand
Posts: 103
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Can somebody tell me why this works:


while this doesn't?:
 
Tug Wilson
Ranch Hand
Posts: 33
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
list() returns String[]
listFiles() returns File[]

The Strings are file names.

File.toString() is a path.

So you will get differet results

In the first example you don't need it.toString()

In the seccond example you don't need to instantiate the File object
 
Clifton Craig
Ranch Hand
Posts: 103
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I know all that. My problem is the second one throws a wierd error Something like:

no Signature of Script28.listAllFiles can be found...

The recursive call doesn't work and I don't understand why when all i did was change the parameter value.
 
Clifton Craig
Ranch Hand
Posts: 103
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Actually I put the redundant toString and new File call in so that I can easily toggle between the two. I started with the first version and added the toString() for the revised version because what i really need in the closure is a File rather than a filename string. BTW, it works when you change it from a closure to a method. My question is why the closure throws an exception on the recursive call?
 
Tug Wilson
Ranch Hand
Posts: 33
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You have two problems:

1/ listAllFiles isn't available to the closure as it isn't actually declared until the end of the statement which creates the closure

2/ you pass a File object to the recursive call which is expecting a String

This works:



Though I think this is slightly nicer


I think 1/ can be considered a bug. If you would be kind enough to raise a JIRA issue on the Groovy site somebody will take a look at it.
 
Tug Wilson
Ranch Hand
Posts: 33
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In case you are wondering why your first example desn't complain that listallFiles is not defined...

It never calls listAllFiles recursivly. This is because File.list() returns file names not paths. So you are checking if there is a directory in the current working directory with the same name as a file in /home/ccc/jedit/4.2
 
Gregg Bolinger
GenRocket Founder
Ranch Hand
Posts: 15302
6
Chrome IntelliJ IDE Mac OS X
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That is some awesomely concise code considering what it's doing and the code I've written in the past in pure java to do the same thing.
 
Clifton Craig
Ranch Hand
Posts: 103
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Tug,

I knew it was something stoopid on my part. I completely overlooked how the first example wasn't recursively descending the file system.
 
Edward Povazan
Greenhorn
Posts: 3
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Clifton, why not use eachFileRecurse?
 
Tug Wilson
Ranch Hand
Posts: 33
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That is some awesomely concise code considering what it's doing and the code I've written in the past in pure java to do the same thing.


Yes - however, as Ed has pointed out, we can do better that that

Groovy adds lots of extra methods to standard Java classes which add useful functionality. So we have eachDir(), eachFile(), eachFileMatch() and eachFileRecurse(). These all take closures as their last parameter and call the closure with a File object parameter. The eachFileMatch method also takes a regexp to filter the file names.

This means that you can do stuff without all that tedious and error prone boilerplate code.

IDE's can often generate Java boilerplate code with a couple of keystrokes. However, you still have to read and maintain the verbiage. Conciseness of notation as a reading benefit not a writing benefit.
 
Jochen Theodorou
Greenhorn
Posts: 4
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I should say an additional word about the recursive closure. The following lines are giving a quick (and incomplete) overview of the variable resolving process in Groovy. You may not understand all, just keep in mind that it is like an extension to the java way.

Given an expression like "a = b" it is a basic rule to evaluate the right side before the left side. That means we get first the value for b and then assign it to a. In an expression like "int i = 1" we evaluate the 1 to 1 (of course) and assign it to i. But when is i defined? It is defined after the right side is evaluated, because it is on the left side. If you think of Java, where you have an expression like "int i = i" and the later i is a field, then the newly declared i will be initialized with the value of the field i. Any subsequent calls to i in the same block of code will not access the field, but the new local variable i. So keeping that in mind and looking at a closure such as "def c = {c()}" makes it clear, that the c inside the closure is not the c outside.

If I write "c = {c()}" then there must have been either a variable/property c, a dynamic property or a reference to a binding. If not the assignment to c will fail. But this also means, that c is defined in the closure. Given that it works the c will be the closure. Then having a code like

explains itself. The c is known.

But there is more. You can influence the way the closure resolves the c by adding setting a delegate.

the delegate is used as last resort for the variable resolving process. When the closure asks the delegate, a map, for "c", it will answer with the value of d, which is the same as the closure itself. Builder do use this a lot.

I hope I made things not too unclear
 
Clifton Craig
Ranch Hand
Posts: 103
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ed,

Why not use eachFileRecurs?


Because I was born with slightly enlarged fingers and an arguably reduced cranium. Simply put my fat fingers no more than my small brain. That's a much more elegant approach and thanks for the tip.

Jochen,

I was initially assuming that the closure would not be available for reference inside itself but I felt I'd try it anyhow since Groovy has performed many other amazing and magical feats I got used to "trusting it" to figure out what my intentions were. When MY earlier example ran without error I naively figured that it was resolving the closure from within itself. It's not my fault though. You guys made the language too doggone good! Now people like me are looking for it to read our minds, automagically terminate and unwind inifinte recursive loops, understand swear words, and more! Stop doing such a good job and you won't get any more complaints from me.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic