Reputation: 5136
When Scala is discussed, the type system is always mentioned as one of the primary features. It is referred to as powerful, and the primary reason for the language moniker (Scala being short for "scalable language"). Could someone please explain how Scala typing works/why this unique, and how that contributes to the language being scalable?
Upvotes: 30
Views: 3171
Reputation: 19468
A few advantages of Scala's type system over Java's:
Types can be inferred in many cases, instead of being specified explicitly. This is more of a convenience, but it promotes using complicated types.
val map = new Map[String, (String, String)]()
instead of
Map<String, Tuple<String, String>> map = new HashMap<String, Tuple<String, String>>()
Functions can be expressed simply in the type system. If you want to see how powerful this is, consider the guava library as a work-around for Java . It's incredibly constrained and verbose (but still useful).
val double = (x: Int) => x * 2
instead of (using Guava)
Function<Integer, Integer> double = new Function<Integer, Integer>() { @Override public Integer apply(Integer value) { return value * 2; }}
Tuples are a type in Scala, circumventing Java's problem of only being able to return a single value.
Scala supports type Variances so you can specify that SomeObject is a subtype of SomeObject when Cat is a subtype of Thing (or when the reverse relation holds). In java, generics are not covariant, which is often problematic.
Scala supports a limited form of multiple-inheritence using traits. Unlike interfaces (of which multiple can be implemented in Java), traits can define methods and variables.
Arrays are transparently handled like any other class.
You can add methods to existing classes through implicit definitions. For example, you could add a "sum" method to Arrays of Integers.
class IntArray(value: Array[Int]) { def sumIt = value.reduceRight(_+_) }
implicit def pimpArray(xs: Array[Int]) = new IntArray(xs)
Array(1,2,3).sumIt
This is another good resource for some of the above topics: http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-5
Upvotes: 20
Reputation: 297245
I don't think the existing answers are appropriate. Scala has a lot of conveniences, but they are not related to the type system being powerful just because they relate to types. In fact, type inference is in direct conflict with the power of the type system -- were it less powerful, one could have full type inference (like in Haskell).
So,
Next, there are features related to Scala's implicits, which is what merit their inclusion above.
Related to the last comment, implicits and type inference, together, make Scala's type system turing complete. That is, you codify arbitrary programs as types, that will be "run" at compile time by the compiler. Proof here, by way of SKI Calculus, with a "buggy" infinite loop in the types as further demonstration.
The list of features above is quite big and impressive on many points. It is, however, the way Scala combines implicits and type inference to produce static proofs at compile time (such as view bounds and context bounds) that make Scala's type system unique. AFAIK, there is no other language doing that, though there are certainly other languages providing proof capabilities through other means.
Upvotes: 46
Reputation: 2104
Any type system in which you can encode HList, TList and HOF for types is quite powerful IMHO. See http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/ for more information.
Upvotes: 3
Reputation: 54584
In addition to schmmd's excellent answer, Scala's type system has even more important features:
object
s are a clean alternative to static
member variables and methods in Java, e.g. an object
has it's own type and can be passed as argumenttype
declarations: you can define aliases for complicated types, like type FactorMap[A] = Map[A, Set[Int]]
The last point is one of my favorites. E.g. you can't write a simple general functor interface in Java. You would need...
public interface Function<A,B> {
public B apply(A a);
}
//not valid Java
public interface Functor<C> {
public <A,B> C<B> map(Function<A,B> fn, C<A> ca);
}
It works if you substitute some concrete type like List
instead of C
. In Java you can abstract over the content of a containter (e.g. by writing `List), but you can't abstract over the container itself. Trust me, I tried to find loopholes (the result was this). In Scala it's a breeze:
trait Functor[C[_]] {
def map[A,B](fn: A => B, ca: C[A]):C[B]
}
object ListFunctor extends Functor[List] {
def map[A,B](fn: A => B, ca: List[A]):List[B] = ca.map(fn)
}
Upvotes: 6
Reputation: 28433
I don't know if you know Java, but imagine Scala's type system like this:
i would love o wrie more, bu my keyboard jus broke, sorry!
Upvotes: 0