jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
  • groovy
  • GROOVY-2724

CLONE -make eachLine,eachByte,eachFile take inject like each

  • Log In
  • Views
    • XML
    • Word
    • Printable

Details

  • Type: Improvement Improvement
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Won't Fix
  • Affects Version/s: 1.0-beta-5
  • Fix Version/s: 1.0-beta-6
  • Component/s: None
  • Labels:
    None

Description

1> [1,2,3].each .inject(0) { i, f | println "${i} ${f}"; ++i }
2> go
0 1
1 2
2 3

1> import java.io.File
2> new File("test.txt").eachLine.inject(0) { i, line | println "${1} ${line}"; ++i }
3> go
No signature of method org.codehaus.groovy.runtime.MethodClosure.inject() is applicable for argument types: (java.lang.Integer, CommandLine8$1) values: [0, CommandLine8$1@5e179a]

The following from John Wilson:

[1,2,3].each creates a closure over the call of each on [1, 2, 3]. This is expected behaviour and is like myObject.myMethod producing a closure over the call of myMethod on myObject.

So:

a = [1,2,3].each
a {println it}

prints
1
2
3

Now the closure generated isn't your common or garden closure, it implements groovy.lang.Range

we can see that by running

for (i in a) {println i}

prints
1
2
3

Now groovy.lang.Range extends java.util.List so the closure is a Collection!

Because the closure is a collection you can call inject on it.

Now the interesting question is how does the system know to make the closure implement Range for each and can we make it do so for eachLine, eachByte, eachFile?

I'm afraid I don't know the answer to this. there's nothing I can see in DefaultGroovyMethods which would tell the compiler to do this. It may well be wired in behaviour.

The fact that this works for each looks to be an unintended consequence of wanting to make the closure a Range (which is useful elsewhere - e.g. in for loops).

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • Work Log
  • History
  • Activity
Hide
Permalink
Jim LoVerde added a comment - 04/Apr/08 4:00 AM

I'm reopening this as a clone, because although there is a "workaround" by declaring a variable and just using the normal iteration as in:

int i = 0
new File("foo.txt").eachLine {
i++; println "current line is $i";
}

The problem is that this approach requires exposing a variable that has no other purpose than the scope of the iteration. I'm not saying that the original poster's suggestion of ".eachLine.inject" is necessarily the best approach, however there should be some mechanism to perform inject to avoid having dangling variables. For example:

new File("foo.txt").eachLineInject(0) { i, line ->
i++; println "current line is $i"
}

The same applies for the collect, find, eachWithIndex, etc helper methods. And it applies not only to File, but also to Reader and other similar situations, where it would be nice to be able to use these methods in a streaming mode.

Show
Jim LoVerde added a comment - 04/Apr/08 4:00 AM I'm reopening this as a clone, because although there is a "workaround" by declaring a variable and just using the normal iteration as in: int i = 0 new File("foo.txt").eachLine { i++; println "current line is $i"; } The problem is that this approach requires exposing a variable that has no other purpose than the scope of the iteration. I'm not saying that the original poster's suggestion of ".eachLine.inject" is necessarily the best approach, however there should be some mechanism to perform inject to avoid having dangling variables. For example: new File("foo.txt").eachLineInject(0) { i, line -> i++; println "current line is $i" } The same applies for the collect, find, eachWithIndex, etc helper methods. And it applies not only to File, but also to Reader and other similar situations, where it would be nice to be able to use these methods in a streaming mode.
Hide
Permalink
Guillaume Laforge added a comment - 04/Apr/08 4:56 AM

There are usually solutions to stick to one-liners, without the need for declaring another variable.

For instance:

new FileReader(".bash_history").iterator().inject(0) { counter, line ->  println line; counter + 1 }

Whenever you can get an interator, for instance, you can use this technique.

So, unless you have specific cases, I'll close this issue as won't fix as there are one-liner workarounds.

Show
Guillaume Laforge added a comment - 04/Apr/08 4:56 AM There are usually solutions to stick to one-liners, without the need for declaring another variable. For instance:
new FileReader(".bash_history").iterator().inject(0) { counter, line ->  println line; counter + 1 }
Whenever you can get an interator, for instance, you can use this technique. So, unless you have specific cases, I'll close this issue as won't fix as there are one-liner workarounds.
Hide
Permalink
Jim LoVerde added a comment - 04/Apr/08 9:51 AM

Thanks Guillaume. I didn't think to try that call on the iterator, since I had only been calling those methods on collections directly. That handles everything I wanted and points out a widely useful idiom.

Maybe I just failed in my RTFM attempts, but adding some examples of using the inject/collect/etc methods on an iterator instead of on a collection (and why you might need to do that if the API exposes an iterator but not a collection directly) might be a good thing to add to the Collections documentation page:
http://groovy.codehaus.org/Collections

Thanks!

Show
Jim LoVerde added a comment - 04/Apr/08 9:51 AM Thanks Guillaume. I didn't think to try that call on the iterator, since I had only been calling those methods on collections directly. That handles everything I wanted and points out a widely useful idiom. Maybe I just failed in my RTFM attempts, but adding some examples of using the inject/collect/etc methods on an iterator instead of on a collection (and why you might need to do that if the API exposes an iterator but not a collection directly) might be a good thing to add to the Collections documentation page: http://groovy.codehaus.org/Collections Thanks!
Hide
Permalink
Guillaume Laforge added a comment - 04/Apr/08 4:48 PM

We've got a user-editable wiki, if you have some time to help us improve our documentation

Show
Guillaume Laforge added a comment - 04/Apr/08 4:48 PM We've got a user-editable wiki, if you have some time to help us improve our documentation
Hide
Permalink
Sam Gaus added a comment - 15/Nov/10 9:51 AM

Perhaps a reason to fix this rather than implement the workaround is if one is already working with an object of type File rather than FileReader?

Show
Sam Gaus added a comment - 15/Nov/10 9:51 AM Perhaps a reason to fix this rather than implement the workaround is if one is already working with an object of type File rather than FileReader?

People

  • Assignee:
    Guillaume Laforge
    Reporter:
    Jim LoVerde
Vote (0)
Watch (0)

Dates

  • Created:
    04/Apr/08 3:46 AM
    Updated:
    15/Nov/10 9:51 AM
    Resolved:
    04/Apr/08 4:56 AM
  • Atlassian JIRA (v5.0.4#731-sha1:3aa7374)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.