There's one thing that you can do concisely and efficiently in Java that you can't in Scala: enumerations. For everything else, even for constructs that are slow in Scala's library, you can get efficient versions working in Scala.
So, for the most part, you don't need to add Java to your code. Even for code that uses enumeration in Java, there's often a solution in Scala that is adequate or good -- I place the exception on enumerations that have extra methods and whose int constant values are used.
As for what to watch out for, here are some things.
If you use the enrich my library pattern, always convert to a class. For example:
// WRONG -- the implementation uses reflection when calling "isWord"
implicit def toIsWord(s: String) = new { def isWord = s matches "[A-Za-z]+" }
// RIGHT
class IsWord(s: String) { def isWord = s matches "[A-Za-z]+" }
implicit def toIsWord(s: String): IsWord = new IsWord(s)
Be wary of collection methods -- because they are polymorphic for the most part, JVM does not optimize them. You need not avoid them, but pay attention to it on critical sections. Be aware that for
in Scala is implemented through method calls and anonymous classes.
If using a Java class, such as String
, Array
or AnyVal
classes that correspond to Java primitives, prefer the methods provided by Java when alternatives exist. For example, use length
on String
and Array
instead of size
.
Avoid careless use of implicit conversions, as you can find yourself using conversions by mistake instead of by design.
Extend classes instead of traits. For example, if you are extending Function1
, extend AbstractFunction1
instead.
Use -optimise
and specialization to get most of Scala.
Understand what is happening: javap
is your friend, and so are a bunch of Scala flags that show what's going on.
Scala idioms are designed to improve correctness and make the code more concise and maintainable. They are not designed for speed, so if you need to use null
instead of Option
in a critical path, do so! There's a reason why Scala is multi-paradigm.
Remember that the true measure of performance is running code. See this question for an example of what may happen if you ignore that rule.
I can't really give an answer to this question, but let me offer some thoughts.
I am a computer engineering student in a university, and last semester me and a group did a large software project in which our primary language was Scala. We did our design the traditional way: use cases, a domain model, sequence diagrams, UML class diagrams; the usual load. And, as you are already aware, they are a poor fit. Here are some reasons.
First, consider sequence diagrams. The feel of a sequence diagram is of a few stable, long-lived, semi-autonomous actors talking to each other. In Scala, objects tend to be created for a short time. Furthermore case classes encourage "dumb" objects, with only data and no code, so the concept of passing messages is out of place. But the hardest challenge for sequence diagrams is that they have no good way of incorporating first-class functions; in an OO design using only a callback here or there it can be made to work, but if that is your primary means of transferring control you will find the sequence diagram reflects little of your actual code.
UML class diagrams are more amenable to Scala; yes, mixins don't come through well, but that is something that could be "tweaked" rather than overhauled. But I think that might be missing the point.
Consider again why Scala has "dumb objects". If you write a case class with no methods:
case class NewInvite(user: User, league: League)
you don't need any methods, because the types of the members promise something about what you can do with them. In fact, they promise everything. And, in every scope within the program, the variables within scope and their types promise something about where the code can go at that point.
So, maybe, if we step back a bit, and, instead of thinking minutely about types per se, design our program in terms of what contexts our code will live in, and what is promised to the programmer (and, eventually, the user) in each of these contexts, we will find a description more appropriate to Scala. However I am only guessing here, and I think you are right that much more needs to be explored in this area.
Best Answer
Some points to consider:
Given all this, you might want to hedge your bets and go for a mixed Java/Scala strategy - i.e. migrate to the JVM platform, and focus initially on Java, but keep open the option to use Scala when your developers are comfortable and/or it fits the problem at hand.
From a management perspective this has lots of advantages:
The downside is that you still have two primary languages to support. But you probably actually have many more than just two already (shell scripts? domain-specific XML formats? config files? rules engines? HTML? Javascript?) so you could argue that it isn't actually that much of a big deal.