5
votes

I saw this thread:

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
      }
    }
  }
}
2
Supplied with an import for File and with a global substitution of iterator for elements, your code compiles.Randall Schulz

2 Answers

7
votes

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.

5
votes

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]