This is the second post of a two-parter. Please read part
1 for context and additional information.

3rd Party Libraries

As mentioned in part 1, Scala is not binary backwards-compatible between major releases.
Although code compiled with 2.10 may work properly with libraries compiled
against 2.9.x, this is hardly recommended and may result in a lot of subtle error
conditions at runtime that are hard to track down. As a result, the recommended practice
is to upgrade all Scala dependencies to versions compiled against 2.10. Fortunately
the Scala ecosystem is very active, so most common libraries had 2.10 builds on announcement
day, but you are still likely to encounter libraries that need to be upgraded because:

They're lagging behind the Scala release schedule and simply haven't released 2.10-compatible
binaries (fortunately, this seems to be extremely rare; in practice all our dependencies
were otherwise resolved);

The specific version you're using does not have a 2.10-compatible release and likely
never will (Squeryl 0.9.5-2);

A 2.10-compatible official release is out but hasn't yet been published to the central
repository (Scalatra 2.0.5).

My experience shows that with a bit of dilligence, practically all our (myriad) dependencies
were fairly easy to migrate to 2.10. In most cases this simply entails switching to
the appropriate artifact ID suffix (_2.10 instead of _2.9.2, see part 1 for associated
rant), in other cases I had to upgrade to a later official release and in rare cases
I had to dig in and replace a dependency with an appropriate fork or snapshot version.
Here is a list of migration notes for some of our dependencies:

The 3.x series runs natively on Scala 2.10 without proxy factories and the like. Syntax
is a bit odd but works like a charm.
The ScalaTest integration is compiled against ScalaTest 2.0-M5b, which forced us to
upgrade.

The Scala class library itself has a number of changes you ought to be aware of before
migrating to 2.10. The really big change is that Scala actors are deprecated in favor
of Akka. You can still use them by importing the scala-actors artifact
from the Scala 2.10 distribution, but it is recommended to migrate fully to the new
actor system as this is also likely to be obsoleted by 2.10.1. The gentle folk at
Typesafe have provided a very comprehensive migration
guide to assist your efforts.

The less prevasive API changes we ran into include:

List.elements is deprecated
in favor of List.iterator;

TraversableOnce.toIndexedSeq no
longer takes a type argument. This was actually quite pervasive in our codebase, causing
plenty of compilation errors, and is easily worked around by removing the type parameter
(which is extraneous to begin with);

Scala actors' Actor.receive method
is now public (previously protected). This had to be rectified in pretty much all
of our existing actors by removing the protected modifer;

Opinions differ among members of our team - some predicted that the migration process
will be much more complex whereas personally, given the relatively high level of maturity
I've come to depend on in the 2.9 series, the migration process actually ended up
being significantly harder than I anticipated. Particularly disconcerting were the
occasional compiler failures which took a lot of time to track down. Practically speaking,
though, the whole migration process took less than 3 days (including documentation),
did not involve additional teammates, and all problems were either resolved or worked
around rather quickly. The Typesafe compiler team has been very helpful in analyzing
and resolving the single bona-fide compiler bug we've run into, and the community
as a whole (on Stack Overflow, Google Groups and elsewhere) was also extremely supportive
and helpful.

On the whole, am I happy with the process? So-so. There is nothing here an experienced
Scala developer should have serious trouble with, but it will take a lot more stability
and predictability for Scala to gain mainstream acceptance in the industry, and that
includes a much easier and more robust migration path to upcoming releases (yes, that
includes migrating from 2.10 to 2.11 when it comes along). That being said, Scala
has been a terrific language to work with in the last couple of years, and the new
features in 2.10 (particularly reflection, macros and string interpolation) should
make this an extremely worthwhile upgrade. We still have a lot of regression testing
to do on the new version, and if anything interesting pops up I'll be sure to post
about it separately (or bitch about it on Twitter...)

Scala 2.10: Migration Case Study - part IIhttp://www.tomergabel.com/PermaLink,guid,851a7271-9bda-403c-a72f-8b13ec552271.aspxhttp://www.tomergabel.com/Scala210MigrationCaseStudyPartII.aspx
Mon, 11 Feb 2013 14:33:11 GMT<p>
This is the second post of a two-parter. Please read <a href="http://www.tomergabel.com/Scala210MigrationCaseStudyPartI.aspx">part
1</a> for context and additional information.
</p>
<p>
<span style="text-decoration: underline;">3rd Party Libraries</span>
</p>
<p>
As mentioned in part 1, Scala is not binary backwards-compatible between major releases.
Although code compiled with 2.10 <em>may</em> work properly with libraries compiled
against 2.9.x, this is hardly recommended and may result in a lot of subtle error
conditions at runtime that are hard to track down. As a result, the recommended practice
is to upgrade <em>all</em> Scala dependencies to versions compiled against 2.10. Fortunately
the Scala ecosystem is very active, so most common libraries had 2.10 builds on announcement
day, but you are still likely to encounter libraries that need to be upgraded because:
</p>
<ul>
<li>
They're lagging behind the Scala release schedule and simply haven't released 2.10-compatible
binaries (fortunately, this seems to be extremely rare; in practice all our dependencies
were otherwise resolved);</li>
<li>
The specific version you're using does not have a 2.10-compatible release and likely
never will (Squeryl 0.9.5-2);</li>
<li>
A 2.10-compatible official release is out but hasn't yet been published to the central
repository (Scalatra 2.0.5).</li>
</ul>
<p>
My experience shows that with a bit of dilligence, practically all our (myriad) dependencies
were fairly easy to migrate to 2.10. In most cases this simply entails switching to
the appropriate artifact ID suffix (_2.10 instead of _2.9.2, see part 1 for associated
rant), in other cases I had to upgrade to a later official release and in rare cases
I had to dig in and replace a dependency with an appropriate fork or snapshot version.
Here is a list of migration notes for some of our dependencies:
</p>
<table border="1" cellpadding="5">
<thead>
<tr>
<td>
<strong>Library</strong></td>
<td>
<strong>Previous</strong></td>
<td>
<strong>New version</strong></td>
<td>
<strong>Comments</strong></td>
</tr>
</thead>
<tbody>
<tr>
<td>
<a href="https://github.com/jorgeortiz85/scala-time">Scala-Time</a></td>
<td>
0.6</td>
<td>
nscala-time 0.2
</td>
<td>
The original library appears to be abandoned and <a href="https://github.com/nscala-time/nscala-time">was
forked</a> on GitHub.<br />
The package changed from <span style="font-family: 'courier new', courier;">org.scala-tools.time</span> to <span style="font-family: 'courier new', courier;">com.github.nscala-time.time</span><span style="font-size: 14px;"> </span></td>
</tr>
<tr>
<td>
<a href="http://scalamock.org/">ScalaMock</a></td>
<td>
2.4</td>
<td>
3.0.1</td>
<td>
The 3.x series runs natively on Scala 2.10 without proxy factories and the like. Syntax
is a bit odd but works like a charm.<br />
The ScalaTest integration is compiled against ScalaTest 2.0-M5b, which forced us to
upgrade.
</td>
</tr>
<tr>
<td>
<a href="http://scalatest.org/">ScalaTest</a></td>
<td>
1.8</td>
<td>
2.0-M5b
</td>
<td>
Minor API changes: <span style="font-family: 'courier new', courier;">Spec</span><span style="font-family: 'courier new', courier;">→</span><span style="font-family: 'courier new', courier;">FunSpec</span>,
parameters changed in <span style="font-family: 'courier new', courier;">Suite.run()</span></td>
</tr>
<tr>
<td>
<a href="http://squeryl.org/">Squeryl</a>
</td>
<td>
0.9.5-2
</td>
<td>
0.9.5-6
</td>
<td>
</td>
</tr>
<tr>
<td>
<a href="http://software.clapper.org/argot/">Argot</a>
</td>
<td>
0.4
</td>
<td>
1.0.0
</td>
<td>
</td>
</tr>
<tr>
<td>
<a href="https://github.com/scala-incubator/scala-io">Scala I/O</a>
</td>
<td>
0.4.1-seq
</td>
<td>
0.4.2
</td>
<td>
</td>
</tr>
<tr>
<td>
<a href="https://github.com/lift/framework/tree/master/core/json">Lift JSON</a> (+<a href="https://github.com/lift/framework/tree/master/core/json-ext">ext</a>)</td>
<td>
2.4
</td>
<td>
2.5-M4
</td>
<td>
</td>
</tr>
<tr>
<td>
<a href="https://github.com/lift/modules/tree/master/facebook">Lift Facebook</a>
</td>
<td>
2.4
</td>
<td>
2.5-SNAPSHOT
</td>
<td>
Had to exclude <span style="font-family: 'courier new', courier;">net.liftweb:lift-webkit_2.10</span> to
avoid dependency conflicts</td>
</tr>
<tr>
<td>
<a href="http://akka.io/">Akka</a></td>
<td>
2.0.4
</td>
<td>
2.1
</td>
<td>
Scheduling now requires an implicit <span style="font-family: 'courier new', courier;">ExecutionContext</span>.
See <a href="http://doc.akka.io/docs/akka/2.1.0/project/migration-guide-2.0.x-2.1.x.html">migration
guide</a> for details.
</td>
</tr>
<tr>
<td>
<a href="http://www.scalatra.org/">Scalatra</a></td>
<td>
2.0.4
</td>
<td>
2.0.5-SNAPSHOT
</td>
<td>
Official <a href="http://www.scalatra.org/2013/02/06/scalatra2-2-released.html">2.0.5
is out</a>, but has not yet shown up on the central repository, so I ended up going
with the (frozen) 2.0.5 snapshot artifacts</td>
</tr>
<tr>
<td>
<a href="http://www.scalatra.org/">Scalatra</a>
</td>
<td>
2.1.1
</td>
<td>
2.2.0
</td>
<td>
scalatra-akka module <a href="http://notes.implicit.ly/post/42420935465/scalatra-2-2-0">has
been folded back</a> into the core artifact as of 2.2.0.</td>
</tr>
<tr>
<td>
<a href="https://www.assembla.com/spaces/scala-graph/wiki">Graph for Scala</a></td>
<td>
1.5.1</td>
<td>
1.6.1
</td>
<td>
</td>
</tr>
</tbody>
</table>
<p>
</p>
<p>
<span style="text-decoration: underline;">Scala Library Changes</span>
</p>
<p>
The Scala class library itself has a number of changes you ought to be aware of before
migrating to 2.10. The really big change is that Scala actors are deprecated in favor
of Akka. You can still use them by importing the <span style="font-family: 'courier new', courier;">scala-actors</span> artifact
from the Scala 2.10 distribution, but it is recommended to migrate fully to the new
actor system as this is also likely to be obsoleted by 2.10.1. The gentle folk at
Typesafe have provided a very comprehensive <a href="http://docs.scala-lang.org/overviews/core/actors-migration-guide.html">migration
guide</a> to assist your efforts.
</p>
<p>
The less prevasive API changes we ran into include:
</p>
<ul>
<li>
<span style="font-family: 'courier new', courier;">List.elements </span>is deprecated
in favor of <span style="font-family: 'courier new', courier;">List.iterator</span>;</li>
<li>
<span style="font-family: 'courier new', courier;">TraversableOnce.toIndexedSeq</span> no
longer takes a type argument. This was actually quite pervasive in our codebase, causing
plenty of compilation errors, and is easily worked around by removing the type parameter
(which is extraneous to begin with);</li>
<li>
Scala actors' <span style="font-family: 'courier new', courier;">Actor.receive</span> method
is now public (previously protected). This had to be rectified in pretty much all
of our existing actors by removing the <span style="font-family: 'courier new', courier;">protected</span> modifer;</li>
<li>
Occasional subtle API changes requiring minor code fixes. For example, see this <a href="http://stackoverflow.com/questions/9487425/enumeration-and-mapping-with-scala-2-10">question
on StackOverflow</a>.</li>
</ul>
<p>
<br />
<span style="text-decoration: underline;">Summary</span>
</p>
<p>
Opinions differ among members of our team - some predicted that the migration process
will be much more complex whereas personally, given the relatively high level of maturity
I've come to depend on in the 2.9 series, the migration process actually ended up
being significantly harder than I anticipated. Particularly disconcerting were the
occasional compiler failures which took a lot of time to track down. Practically speaking,
though, the whole migration process took less than 3 days (including documentation),
did not involve additional teammates, and all problems were either resolved or worked
around rather quickly. The Typesafe compiler team has been very helpful in analyzing
and resolving the single bona-fide compiler bug we've run into, and the community
as a whole (on Stack Overflow, Google Groups and elsewhere) was also extremely supportive
and helpful.
</p>
<p>
On the whole, am I happy with the process? So-so. There is nothing here an experienced
Scala developer should have serious trouble with, but it will take a lot more stability
and predictability for Scala to gain mainstream acceptance in the industry, and that
includes a much easier and more robust migration path to upcoming releases (yes, that
includes migrating from 2.10 to 2.11 when it comes along). That being said, Scala
has been a terrific language to work with in the last couple of years, and the new
features in 2.10 (particularly reflection, macros and string interpolation) should
make this an extremely worthwhile upgrade. We still have a lot of regression testing
to do on the new version, and if anything interesting pops up I'll be sure to post
about it separately (or bitch about it on <a href="http://twitter.com/@tomerg">Twitter</a>...)
</p>
<img width="0" height="0" src="http://www.tomergabel.com/aggbug.ashx?id=851a7271-9bda-403c-a72f-8b13ec552271" />DevelopmentDevelopment/Scalahttp://www.tomergabel.com/Trackback.aspx?guid=63886411-d1b2-42f7-ae3e-833d2026be73http://www.tomergabel.com/pingback.aspxhttp://www.tomergabel.com/PermaLink,guid,63886411-d1b2-42f7-ae3e-833d2026be73.aspxTomer Gabel

I just spent a few days migrating our codebase from Scala 2.9.2 to Scala
2.10. A quick search found very little in the way of migration guides and studies,
so it seemed appropriate to document my experiences and offer what tips I managed
to collect on the way.

General Observations

This process should not be undertaken lightly, and its implementation inevitably depends
on your resources and team composition. The group (or person) charged with migrating
the codebase should, at the very least, consist of an experienced Scala developer
not afraid to get his or her hands dirty.

The migration is not an entirely smooth process - there are plenty of (fortunately
fairly minor) breaking changes in the Scala APIs, and since Scala does not yet feature
binary backwards compatibility between major versions (2.9→2.10→2.11...), so expect
some inevitable library upgrades and the potential complexities inherent in any such
update. The specific issues I encountered are documented in their respective sections
below.

Unfortunately there is not much I can offer in the way of preparation; these are the
obvious steps:

Familiarize yourself with Scala
2.10. Make sure you know what you’re getting in exchange for investing time and effort
on the migration process and early-bird issues;

Work in an isolated branch and pull changes from the master branch often;

Commit early, commit often. Try to keep your commits small and well-documented, so
you have good revert checkpoints for when things go wrong;

Keep the affected code to a minimum. The fewer changes, the easier it will be to isolate
problems down the road.

If you’ve read so far and still can’t wait for 2.10.1, I hope the next few sections
will save you some time and pain.

Toolchain

To start things off I switched the build to use Scala 2.10. Our project runs on Maven
in lieu of SBT (topic for another post), and we use David Bernard’s excellent scala-maven-plugin,
which deduces the Scala version from the scala-library dependency.

The convention for the Scala version suffix has changed between 2.9 and 2.10: for
example, argot2.9.2 is now argot2.10 -
no revision for the 2.10 series. This rendered the suffix macro we employ useless,
because annoyingly the Scala librariesthemselves (e.g. scalap or scala-compiler)
actually use the full version number, so we ended up needing two macros (a
“raw” Scala version and a suffix).

Fortunately, at least as far as Maven is concerned the rest was smooth sailing. I
next turned my attention to IntelliJ IDEA - I wanted to make sure an existing workspace
can be reused with the migrated codebase, otherwise my entire team will have to undergo
the inconvenience of starting from scratch on a clean working copy. Fortunately the
process turned out to be quite painless (on IDEA 12.0.3 with Scala plugin build 0.7.121),
with the following caveats:

Project FSC settings had to be manually changed to use the 2.10 compiler bundle (it
remained on the default 2.9.2). This proved to be a moot point, because:

The much-touted IDEA external
build mode finally works consistently for the first time (and it uses the significantly
better SBT compiler)!

On the negative side, IDEA does not seem to handle compiler failures (as opposed to
compilation errors) gracefully, missing a lot of detail in the output. As I ran into
quite a few of these (details below), I ended up doing most of the compilation tests
with Maven directly.

Beyond setting up a build job for the new branch, Jenkins posed no issues.
To summarize, from a toolchain standpoint, this was actually a fairly smooth process.

Language/Compiler

I was surprised and somewhat disheartened to find that, after some initial compilation
attempts, it became evident that I missed every single mark in my code risk
predictions. Where I expected most language-level headaches I encountered none, and
seemingly simple and risk-free code ended up taking most of the time working on this
process.

First off, the Scala 2.10 compiler is much stricter than the earlier 2.9.x
series. It has a few new heuristics that ended up triggering very often on our codebase;
some are simply the result of messy code or design, but most are new best practices
adopted by the compiler team at Typesafe:

“warning: This catches all Throwables. If this is really intended, use `case _
: Throwable` to clear this warning.”
We wrap-and-throw or swallow a lot of exceptions, and for brevity’s sake often use
the shorter catch { case _ => }. A catch block is analogous to a partial
function from Throwable, and there are undoubtedly cases where the distinction matters.
We’ll clean these up iteratively by qualifying that we’re only catching Exceptions.

“non-variable type argument B[T] in type A[B[T]] is unchecked since it is eliminated
by erasure”
The 2.10 compiler is actually quite helpful in warning you when generic code may not
behave as expected. This is just one example of such a warning.

“error: overloaded method methodName needs result type”
The 2.10 compiler requires you to specify result types on most (all?) types
of method overloading. Not much work here.

Case classes can no longer derive from other case classes, which makes a whole lot
of sense if you consider the typesystem; 2.9.x had a whole variety of bugs and edge-cases
relating to case class inheritance and companion objects, including some unwieldy
constructor syntax. 2.10 simply does away with the complexity and potential ambiguity,
which will break existing code. Since such class hierarchies are inherently problematic,
I see this as an opportunity to refactor them properly; extractor
objects were often useful for that task.

In one case we ran into stricter cyclic dependency analysis on the part of 2.10 -
an object extended a class and passed a member of another object as a constructor
parameter. The second object referenced the first, which compiled fine under 2.9.2
but resulted in a cyclic dependency error with 2.10. As the original design was hard
to understand I refactored the code to be a bit simpler, which resolved the problem
satisfactorily.

Manifests are deprecated in favor of TypeTags and the new reflection library built
into 2.10 (certainly one if its most anticipated and celebrated features), but are
still functional. We haven’t migrated to the new APIs yet, and that process will likely
deserve a post all on its own; read this excellent
answer on Stack Overflow for an introduction to TypeTags.

Beyond these and the occasional minor syntax change, the 2.10 compiler proved a somewhat
difficult beast to tame:

Ran into crazily-detailed compiler failures that clearly (though long-windedly) indicated
that I need to manually add scala-reflect to the classpath;

Missing or conflicting dependencies, typically due to mishandling POMs, resulted in
what I ended up dubbing the Spontaneous Compiler Combustion phenomenon: a
cryptic compilation failure, complete with what appears to be an AST dump and full-blown
debug information. Tracking the occasional familiar type name in the compiler log
can be helpful in tracking down the dependency at fault (this was the case in all
but one of the occurrences), but the error itself is completely inscrutable.

The one case was, unfortunately, a proper compiler bug logged as SI-7109,
which has to do with consuming a package-protected (or -private) trait/class from
another trait/class with the same accessibility. Jason Zaugg of Typesafe (@retronym)
was extremely helpful in analysing the compiler output and producing a reproduction
case, which I haven’t been able to do on my own. Until a fix is included and released,
I’ve worked around this by temporarily commenting out the problematic qualifiers.

Update (2013-02-12): Ran into another compiler bug that causes a runtime ClassFormatError.
We've managed to identify, reproduce and work around the problem; see SI-7120 on
the Typesafe JIRA.

Lastly, it’s worth noting that the 2.10 compiler is significantly heavier than the
older 2.9.x series: it appears to require 50-100% more permgen space, and compile
times are up x2 on average and up to x10 on a clean, fresh build.
This seems consistent on both my laptop and the build server, which use different
CPUs and OS. A quick check (top and jstat -gcutil) showed the compiler
process to be single-threaded and CPU-bound, as it consistently utilizes 100% of a
single core. GC activity was low to the point of negligible, so it appears the new
compiler is actually a step back in terms of compilation throughput. I hope subsequent
2.10.x releases focus primarily on compilation stability and performance.

That’s it for today; next post will be
up in a day or twois
up and focuses on the Scala library, dependencies and miscellanea.

Scala 2.10: Migration Case Study - part Ihttp://www.tomergabel.com/PermaLink,guid,63886411-d1b2-42f7-ae3e-833d2026be73.aspxhttp://www.tomergabel.com/Scala210MigrationCaseStudyPartI.aspx
Mon, 11 Feb 2013 00:57:09 GMT<p>
I just spent a few days migrating our codebase from Scala 2.9.2 to <a href="http://www.scala-lang.org/node/27499">Scala
2.10</a>. A quick search found very little in the way of migration guides and studies,
so it seemed appropriate to document my experiences and offer what tips I managed
to collect on the way.
</p>
<p>
<span style="text-decoration: underline;">General Observations</span>
</p>
<p>
This process should not be undertaken lightly, and its implementation inevitably depends
on your resources and team composition. The group (or person) charged with migrating
the codebase should, at the very least, consist of an experienced Scala developer
not afraid to get his or her hands dirty.
</p>
<p>
The migration is not an entirely smooth process - there are plenty of (fortunately
fairly minor) breaking changes in the Scala APIs, and since Scala does not yet feature
binary backwards compatibility between major versions (2.9→2.10→2.11...), so expect
some inevitable library upgrades and the potential complexities inherent in any such
update. The specific issues I encountered are documented in their respective sections
below.
</p>
<p>
Unfortunately there is not much I can offer in the way of preparation; these are the
obvious steps:
</p>
<ul>
<li>
<a href="http://www.scala-lang.org/node/27499">Familiarize yourself</a> with Scala
2.10. Make sure you know what you’re getting in exchange for investing time and effort
on the migration process and early-bird issues;</li>
<li>
Work in an isolated branch and pull changes from the master branch often;</li>
<li>
Commit early, commit often. Try to keep your commits small and well-documented, so
you have good revert checkpoints for when things go wrong;</li>
<li>
Keep the affected code to a minimum. The fewer changes, the easier it will be to isolate
problems down the road.</li>
</ul>
<p>
If you’ve read so far and still can’t wait for 2.10.1, I hope the next few sections
will save you some time and pain.
</p>
<p>
<span style="text-decoration: underline;">Toolchain</span>
</p>
<p>
To start things off I switched the build to use Scala 2.10. Our project runs on Maven
in lieu of SBT (topic for another post), and we use David Bernard’s excellent <a href="http://davidb.github.com/scala-maven-plugin/">scala-maven-plugin</a>,
which deduces the Scala version from the scala-library dependency.
</p>
<p>
The convention for the Scala version suffix has changed between 2.9 and 2.10: for
example, <tt>argot<em>2.9.2</em></tt><em> is now <tt>argot</tt></em><tt>2.10</tt> -
no revision for the 2.10 series. This rendered the suffix macro we employ useless,
because annoyingly the Scala <em>libraries</em>themselves (e.g. scalap or scala-compiler)
actually use the full version number, so we ended up needing <em>two</em> macros (a
“raw” Scala version and a suffix).
</p>
<p>
Fortunately, at least as far as Maven is concerned the rest was smooth sailing. I
next turned my attention to IntelliJ IDEA - I wanted to make sure an existing workspace
can be reused with the migrated codebase, otherwise my entire team will have to undergo
the inconvenience of starting from scratch on a clean working copy. Fortunately the
process turned out to be quite painless (on IDEA 12.0.3 with Scala plugin build 0.7.121),
with the following caveats:
</p>
<ul>
<li>
Code analysis appears to miss some cases of stricter compilation compared to 2.9.x
(see below);</li>
<li>
Code analysis occasionally identifies relative import statements as erroneous (e.g. <tt>import
util.Random</tt>);</li>
<li>
Project FSC settings had to be manually changed to use the 2.10 compiler bundle (it
remained on the default 2.9.2). This proved to be a moot point, because:</li>
<li>
The much-touted IDEA <a href="http://blog.jetbrains.com/scala/2012/12/28/a-new-way-to-compile/">external
build mode</a> finally works consistently for the first time (and it uses the significantly
better SBT compiler)!</li>
<li>
On the negative side, IDEA does not seem to handle compiler failures (as opposed to
compilation errors) gracefully, missing a lot of detail in the output. As I ran into
quite a few of these (details below), I ended up doing most of the compilation tests
with Maven directly.</li>
</ul>
<p>
Beyond setting up a build job for the new branch, Jenkins posed no issues.<br />
To summarize, from a toolchain standpoint, this was actually a fairly smooth process.
</p>
<p>
<span style="text-decoration: underline;">Language/Compiler</span>
</p>
<p>
I was surprised and somewhat disheartened to find that, after some initial compilation
attempts, it became evident that I missed <em>every single mark</em> in my code risk
predictions. Where I expected most language-level headaches I encountered none, and
seemingly simple and risk-free code ended up taking most of the time working on this
process.
</p>
<p>
First off, the Scala 2.10 compiler is <em>much stricter</em> than the earlier 2.9.x
series. It has a few new heuristics that ended up triggering very often on our codebase;
some are simply the result of messy code or design, but most are new best practices
adopted by the compiler team at Typesafe:
</p>
<ul>
<li>
<tt>“warning: This catches all Throwables. If this is really intended, use `case _
: Throwable` to clear this warning.”</tt>
<br class="kix-line-break" />
We wrap-and-throw or swallow a lot of exceptions, and for brevity’s sake often use
the shorter <tt>catch { case _ => }</tt>. A catch block is analogous to a partial
function from Throwable, and there are undoubtedly cases where the distinction matters.
We’ll clean these up iteratively by qualifying that we’re only catching Exceptions.<br />
<br class="kix-line-break" />
</li>
<li>
<tt>“non-variable type argument B[T] in type A[B[T]] is unchecked since it is eliminated
by erasure”</tt>
<br class="kix-line-break" />
The 2.10 compiler is actually quite helpful in warning you when generic code may not
behave as expected. This is just one example of such a warning.<br />
<br class="kix-line-break" />
</li>
<li>
<tt>“error: overloaded method methodName needs result type”</tt>
<br class="kix-line-break" />
The 2.10 compiler <em>requires</em> you to specify result types on most (all?) types
of method overloading. Not much work here.</li>
<li>
Case classes can no longer derive from other case classes, which makes a whole lot
of sense if you consider the typesystem; 2.9.x had a whole variety of bugs and edge-cases
relating to case class inheritance and companion objects, including some unwieldy
constructor syntax. 2.10 simply does away with the complexity and potential ambiguity,
which will break existing code. Since such class hierarchies are inherently problematic,
I see this as an opportunity to refactor them properly; <a href="http://www.scala-lang.org/node/112">extractor
objects</a> were often useful for that task.<br />
<br class="kix-line-break" />
</li>
<li>
In one case we ran into stricter cyclic dependency analysis on the part of 2.10 -
an object extended a class and passed a member of another object as a constructor
parameter. The second object referenced the first, which compiled fine under 2.9.2
but resulted in a cyclic dependency error with 2.10. As the original design was hard
to understand I refactored the code to be a bit simpler, which resolved the problem
satisfactorily.<br />
<br class="kix-line-break" />
</li>
<li>
Manifests are deprecated in favor of TypeTags and the new reflection library built
into 2.10 (certainly one if its most anticipated and celebrated features), but are
still functional. We haven’t migrated to the new APIs yet, and that process will likely
deserve a post all on its own; read this <a href="http://stackoverflow.com/a/12232195/11558">excellent
answer</a> on Stack Overflow for an introduction to TypeTags.<br class="kix-line-break" />
</li>
</ul>
<p>
Beyond these and the occasional minor syntax change, the 2.10 compiler proved a somewhat
difficult beast to tame:
</p>
<ul>
<li>
Ran into crazily-detailed compiler failures that clearly (though long-windedly) indicated
that I need to manually add <tt>scala-reflect</tt> to the classpath;<br />
<br class="kix-line-break" />
</li>
<li>
Missing or conflicting dependencies, typically due to mishandling POMs, resulted in
what I ended up dubbing the <em>Spontaneous Compiler Combustion phenomenon</em>: a
cryptic compilation failure, complete with what appears to be an AST dump and full-blown
debug information. Tracking the occasional familiar type name in the compiler log
can be helpful in tracking down the dependency at fault (this was the case in all
but one of the occurrences), but the error itself is completely inscrutable.<br />
<br class="kix-line-break" />
</li>
<li>
The one case was, unfortunately, a proper compiler bug logged as <a href="https://issues.scala-lang.org/browse/SI-7091">SI-7109</a>,
which has to do with consuming a package-protected (or -private) trait/class from
another trait/class with the same accessibility. Jason Zaugg of Typesafe (<a href="https://twitter.com/retronym">@retronym</a>)
was extremely helpful in analysing the compiler output and producing a reproduction
case, which I haven’t been able to do on my own. Until a fix is included and released,
I’ve worked around this by temporarily commenting out the problematic qualifiers.<br class="kix-line-break" />
<br />
</li>
<li>
<b>Update (2013-02-12)</b>: Ran into another compiler bug that causes a runtime <tt>ClassFormatError</tt>.
We've managed to identify, reproduce and work around the problem; see <a href="https://issues.scala-lang.org/browse/SI-7120">SI-7120</a> on
the Typesafe JIRA.<br class="kix-line-break" />
</li>
</ul>
<p>
Lastly, it’s worth noting that the 2.10 compiler is significantly heavier than the
older 2.9.x series: it appears to require 50-100% more permgen space, and compile
times are up x2 on average and <strong>up to x10</strong> on a clean, fresh build.
This seems consistent on both my laptop and the build server, which use different
CPUs and OS. A quick check (<tt>top</tt> and <tt>jstat -gcutil</tt>) showed the compiler
process to be single-threaded and CPU-bound, as it consistently utilizes 100% of a
single core. GC activity was low to the point of negligible, so it appears the new
compiler is actually a step back in terms of compilation throughput. I hope subsequent
2.10.x releases focus primarily on compilation stability and performance.
</p>
<p>
</p>
<p>
That’s it for today; next post <span style="text-decoration: line-through;">will be
up in a day or two</span> <a href="http://www.tomergabel.com/Scala210MigrationCaseStudyPartII.aspx">is
up</a> and focuses on the Scala library, dependencies and miscellanea.
</p>
<img width="0" height="0" src="http://www.tomergabel.com/aggbug.ashx?id=63886411-d1b2-42f7-ae3e-833d2026be73" />DevelopmentDevelopment/Scala