views:

193

answers:

2

I saw this thread:

http://stackoverflow.com/questions/1243794/what-are-the-biggest-differences-between-scala-2-8-and-scala-2-7

It seems to cover some changes, but the first compile problems I've hit don't seem to be mentioned. Any suggestions?

  • kinds of the type arguments (Iterable[Any] with (A with Int) => Any) do not conform to the expected kinds of the type parameters (type CC) in class GenericCompanion. Iterable[Any] with (A with Int) => Any's type parameters do not match type CC's expected parameters: has no type parameters, but type CC has one
  • object creation impossible, since method iterator in trait IterableLike of type => Iterator[java.io.File] is not defined
  • object creation impossible, since method iterator in trait IterableLike of type => Iterator[V] is not defined
  • overriding method elements in trait IterableLike of type => Iterator[java.io.File]; method elements needs `override' modifier
  • overriding method elements in trait IterableLike of type => Iterator[V]; method elements needs `override' modifier

Here's the code in question:

/**
 * Filesystem walker.
 * <p>
 * Less magic version of: http://rosettacode.org/wiki/Walk_Directory_Tree#Scala
 */
object FsWalker {
  /**
   * Recursive iterator over all files (and directories) in given directory.
   */
  def walk(f: File): Iterable[File] = new Iterable[File] {
    def elements = {
      if (f.isDirectory()) {
        // recurse on our child files
        f.listFiles.elements.flatMap(child => FsWalker.walk(child).elements)
      } else {
        // just return given file wrapped in Iterator
        Seq(f).elements
      }
    }
  }
}
+6  A: 

The former elements is now iterator.

You should compile with -Xmigration for helpful hints on how to port your code from 2.7 to 2.8.

Randall Schulz
Thanks, that was it. I will try out -Xmigration
Alex Black
+5  A: 

The key here is to make sure you use the method iterator with an Iterable. Scala 2.8.0 also did a lot to ensure that types are consistent across collection calls.

scala> val x = new Iterable[String] {
     | def iterator = List("HAI", "YOU", "GUYS").iterator
     | }
x: java.lang.Object with Iterable[String] = line18(HAI, YOU, GUYS)

I would also consider using a Stream instead of an iterator. The iterator approach will construct the entire set of files when calling the iterator method. A stream could be lazy.

scala> def files(f : File) : Stream[File] = {
     |   if(f.isDirectory) {                   
     |     f.listFiles.toStream.map(files).flatten
     |   } else Stream(f)
     | }
files: (f: java.io.File)Stream[java.io.File]

scala> files(new File("/home/jsuereth/projects/scala/scala"))
res1: Stream[java.io.File] = Stream(/home/jsuereth/projects/scala/scala/build/manmaker/classes/scala/man1/sbaz.class, ?)

scala> res1 take 10 foreach println
/home/jsuereth/projects/scala/scala/build/manmaker/classes/scala/man1/sbaz.class
/home/jsuereth/projects/scala/scala/build/manmaker/classes/scala/man1/scala$$anon$1.class
...

Alternatively, if you want to include directories in the stream, try the following:

scala> def files_with_dirs(f : File) : Stream[File] = {
     | if(f.isDirectory) Stream.cons(f, f.listFiles.toStream.map(files).flatten)
     | else Stream(f)
     | }
files_with_dirs: (f: java.io.File)Stream[java.io.File]
jsuereth