I\'ve written a rather large program in Scala 2.7.5, and now I\'m looking forward to version 2.8. But I\'m curious about how this big leap in the evolution of Scala will aff
You can find here a preview of new feature in Scala2.8 (April 2009), completed with recent this article (June 2009)
"Rewriting code" is not an obligation (except for using some of the improved Collections), but some features like continuation (Wikipedia: an abstract representation of the control state, or the "rest of computation" or "rest of code to be executed") can give you some new ideas. A good introduction is found here, written by Daniel (who has also posted a much more detailed and specific answer in this thread).
Note: Scala on Netbeans seems to work with some 2.8 nightly-build (vs. the official page for 2.7.x)
Here's a checklist from Eric Willigers, who has been using Scala since 2.2. Some of this stuff will seem dated to more recent users.
* Explicitly import from outer packages *
Suppose we have
package a
class B
Change
package a.c
class D extends B
to
package a.c
import a.B
class D extends B
or
package a
package c
class D extends B
* Use fully qualified package name when importing from outer package *
Suppose we have
package a.b
object O { val x = 1 }
Change
package a.b.c
import b.O.x
to
package a.b.c
import a.b.O.x
* When explicitly specifying type parameters in container method calls, add new type parameters *
Change
list.map[Int](f)
to
list.map[Int, List[Int]](f)
Change
map.transform[Value](g)
to
map.transform[Value, Map[Key, Value]](g)
* Create sorted map using Ordering instead of conversion to Ordered *
[scalac] found : (String) => Ordered[String]
[scalac] required: Ordering[String]
[scalac] TreeMap[String, Any](map.toList: _*)(stringToCaseInsensitiveOrdered _)
* Import the implicit conversions that replace scala.collection.jcl *
* Immutable Map .update becomes .updated *
*** Migrate from newly deprecated List methods --
*elements
*remove
*sort
*List.flatten(someList)
*List.fromString(someList, sep)
*List.make
*** Use List methods *
diff
*iterator
*filterNot
*sortWith
*someList.flatten
*someList.split(sep)
*List.fill
* classpath when using scala.tools.nsc.Settings *
http://thread.gmane.org/gmane.comp.lang.scala/18245/focus=18247 settings.classpath.value = System.getProperty("java.class.path")
* Avoid error: _ must follow method; cannot follow (Any) => Boolean *
Replace
list.filter(that.f _)
with
list.filter(that f _)
or
list.filter(that.f(_))
> > >
* Migrate from deprecated Enumeration methods
iterator
map
* Use Enumeration methodsvalues.iterator
values.map
* Migrate from deprecated
Iterator.fromValues(a, b, c, d)
* UseIterator(a, b, c, d)
* Avoid deprecated type
Collection
* UseIterable
instead* Change initialisation order *
Suppose we have
trait T {
val v
val w = v + v
}
Replace
class C extends T {
val v = "v"
}
with
class C extends {
val v = "v"
} with T
* Avoid unneeded
val
infor (val x <- ...)
** Avoid trailing commas *
When you migrate, the compiler can provide you with some safety nets.
-deprecation
, and follow the
recommendations from all deprecation
warnings. Update your code to use unnnested packages. This can be done mechanically by repeatedly running this regular expression search replace.
s/^(package com.example.project.*)\.(\w+)/$1\npackage $2/g
Compile with 2.8.0 compiler, using paranoid command line options -deprecation -Xmigration -Xcheckinit -Xstrict-warnings -Xwarninit
If you receive errors the error could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
, you need to add an implicit parameter (or equivalently, a context bound), on a type parameter.
Before:
scala> def listToArray[T](ls: List[T]): Array[T] = ls.toArray
<console>:5: error: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
def listToArray[T](ls: List[T]): Array[T] = ls.toArray ^
After:
scala> def listToArray[T: Manifest](ls: List[T]): Array[T] = ls.toArray
listToArray: [T](ls: List[T])(implicit evidence$1: Manifest[T])Array[T]
scala> def listToArray[T](ls: List[T])(implicit m: Manifest[T]): Array[T] = ls.toArray
listToArray: [T](ls: List[T])(implicit m: Manifest[T])Array[T]
Any method that calls listToArray
, and itself takes T
as a type parameter, must also accept the Manifest as an implicit parameter. See the Arrays SID for details.
Before too long, you'll encounter an error like this:
scala> collection.Map(1 -> 2): Map[Int, Int]
<console>:6: error: type mismatch;
found : scala.collection.Map[Int,Int]
required: Map[Int,Int]
collection.Map(1 -> 2): Map[Int, Int]
^
You need to understand that the type Map
is an alias in Predef for collection.immutable.Map
.
object Predef {
type Map[A, B] = collection.immutable.Map[A, B]
val Map = collection.immutable.Map
}
There are three types named Map
-- a read-only interface: collection.Map
, an immutable implementation: collection.immutable.Map
, and a mutable implementation: collection.mutable.Map
. Furthermore, the library defines the behaviour in a parallel set of traits MapLike
, but this is really an implementation detail.
Use the generated copy
method of case classes.
scala> case class Foo(a: Int, b: String)
defined class Foo
scala> Foo(1, "a").copy(b = "b")
res1: Foo = Foo(1,b)
List
to Seq
or Iterable
or Traversable
. Because collection classes are in a clean hierarchy, can you accept a more general type.There are many other new features that can be safely ignored as you start migrating, for example @specialized
and Continuations.
VonC's answer is hard to improve on, so I won't even try to. I'll cover some other stuff not mentioned by him.
First, some deprecated stuff will go. If you have deprecation warnings in your code, it's likely it won't compile anymore.
Next, Scala's library is being expanded. Mostly, common little patterns such as catching exceptions into Either
or Option
, or converting an AnyRef into an Option with null
mapped into None
. These things can mostly pass unnoticed, but I'm getting tired of posting something on the blog and later having someone tell me it's already on Scala 2.8. Well, actually, I'm not getting tired of it, but, rather, and happily, used to it. And I'm not talking here about the Collections, which are getting a major revision.
Now, it would be nice if people posted actual examples of such library improvements as answers. I'd happily upvote all such answers.
REPL is not getting just command-completion. It's getting a lot of stuff, including the ability to examine the AST for an object, or the ability to insert break points into code that fall into REPL.
Also, Scala's compiler is being modified to be able to provide fast partial compilation to IDEs, which means we can expect them to become much more "knowledgable" about Scala -- by querying the Scala compiler itself about the code.
One big change is likely to pass unnoticed by many, though it will decrease problems for library writers and users alike. Right now, if you write the following:
package com.mystuff.java.wrappers
import java.net._
You are importing not Java's net
library, but com.mystuff.java
's net
library, as com
, com.mystuff
, com.mystuff.java
and com.mystuff.java.wrappers
all got within scope, and java
can be found inside com.mystuff
. With Scala 2.8, only wrappers
gets scoped. Since, sometimes, you want some of the rest to be in Scope, an alternative package
syntax is now allowed:
package com.mystuff.factories
package ligthbulbs
which is equivalent to:
package com.mystuff.factories {
package lightbulbs {
...
}
}
And happens to get both factories
and lightbulbs
into scope.
Will I need to rewrite anything?
def takesArray(arr: Array[AnyRef]) {…}
def usesVarArgs(obs: AnyRef*) {
takesArray(obs)
}
needs to become
def usesVarArgs(obs: AnyRef*) {
takesArray(obs.toArray)
}
I had to visit the IRC channel for that one, but then realized I should have started here.