Scala turns 10
article.gmane.org
article.gmane.org
[1] - https://github.com/scala/scala/blob/master/src/library/scala...
The whole situation just drips with arrogance... "we have a magic number, and if you hit it, you suck"
You mean like Java does since ... forever?
I'm very much looking forward to fixing this ridiculous situation. Onboarding a new hire to Scala with this being the first thing they run in to isn't pretty.
Yes the same here, and I haven't found an idea that's overall better, taking everything into account.
This will break some tools, like Play's forms, that need you to pass to a couple of serialization/deserialization functions.
Shapeless will probably be fine, or at least, since it is macro based, it will be able to go around the missing unapply and extract the fields directly, like pattern matching does. (I don't know shapeless enough to go into more details)
XML Support as selling Point + Multiparadigm == !mainstream?
I agree that scala has its quirks (IMO, the type system is way too complicated), but to have dismissed it based on two apparently unrelated features 8 years ago seems a little strange.
(This is what it looked like yesterday: https://web.archive.org/web/20140119030617/http://www.scala-... )
Either they're doing a throwback thing for the anniversary or that's a remarkably coincidental server issue.
After that class, I thought I would ever see it again.
If it was weaker (á la JVM) it would be fine, if it was more powerful it could represent stuff at runtime.
I'm trying to find a link to the paper which says there is not an efficient one-to-one mapping from Scala to CLR
The death of the .NET port can directly be attributed to Microsoft's marketing of the platform. If they manage to make people question whether .NET will still be alive in 10 years, it's no surprise that people start dropping support for it.
There is nothing which can't be fixed by focused work on all the bits and pieces which need work, and that's exactly what the scalac compiler developers are doing most of the time.
So many improvements are coming in every week that I can hardly stand using an older compiler version, because I always know that so much stuff has already substantially improved.
Despite what some people say, life in Scala-land is pretty damn good.
Contrary to popular opinion, erasure is a superior solution to reification for many reasons, and this is one of them.
Java's generics can't be built on top of the CLR's reified generics, but this goes for other languages as well - Haskell, ML, Scala, you name it. Basically, reified generics work well in case you design the language in combination with the VM, otherwise it becomes a huge PITA.
FYI, the CLR's reified generics is one reason for why the JVM is a better target for other languages. For dynamic languages, they are a problem because the bytecode generator has to work around them. For static languages, such as Scala or anything in the ML family, it's a problem because either (a) they are designed for co/contra-variance or (b) they don't support higher-kinded types or (c) they don't support rank-2 types or (d) in case you do need co/contra-variance rules, for some reason Microsoft chose to restrict the declarations only to generic interfaces and delegates, so you can't design a List<+T> class for example (to be honest, I'm not sure if this last one is a limitation of the language or the CLR).
Also, having reified generics is less important than you think. Scala for example can do specialization for primitive types and because the type-system is much stronger, coupled with an awesome collections library and pattern matching, the flow of the types is much better. For example, I can't remember any instance in which I felt the need to do a (obj isInstanceOf List<int>) check, immutable collections can be covariant without issues and for everything else there are type-classes, something which C# sorely lacks.
IMHO, in spite of people's opinion on the matter, Java's type-erased generics is one of its best features.
I was under the impression that Scala just used Manifests and type tokens (a la my colleague Neal Gafter's Super Type Tokens) to get around the problem of erasure. I don't see any evidence that this actually works better, though.
scala> val list = List(null, 1, 2, "any")
list: List[Any] = List(null, 1, 2, any)
scala> list.collect { case x: Int => x }
res0: List[Int] = List(1, 2)
scala> Vector(null, "hello", 3).collectFirst { case i: Int => i * 2 }
res1: Option[Int] = Some(6)
scala> import collection.immutable.BitSet
scala> BitSet(1,2,3).map(_ + 1)
res2: immutable.BitSet = BitSet(2, 3, 4)
scala> BitSet(1,2,3).map(_.toString)
res3: immutable.SortedSet[String] = TreeSet(1, 2, 3)
To be honest, tags are indeed needed for creating arrays, since they are reified by the JVM: scala> import scala.reflect.ClassTag
scala> def myAwesomeArray[T : ClassTag] = new Array[T](10)
scala> myAwesomeArray[Int]
res4: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
One common problem is that overriding of parameters doesn't work for containers due to type erasure, so you can't have overrides on type parameters, because the JVM gets in the way (i.e. the following does not work): def sum(list: List[String]) = ???
def sum(list: List[Int]) = ???
However, Scala has something more powerful (type-classes): trait Monoid[T] {
def plus(x: T, y: T): T
def zero: T
}
implicit object IntMonoid extends Monoid[Int] {
def plus(x: Int, y: Int) = x + y
val zero = 0
}
implicit object StringMonoid extends Monoid[String] {
def plus(x: String, y: String) = x + y
val zero = ""
}
def sum[T : Monoid](list: List[T]) = {
val monoid = implicitly[Monoid[T]]
list.foldLeft(monoid.zero)(monoid.plus)
}
scala> sum(List("a", "b", "c", "d"))
res5: String = abcd
scala> sum(List(1,2,3,4))
res6: Int = 10
But wait, we can go much further with implicits that actually dictate the return type: trait SetBuilder[T, R] {
def empty: R
def buildInstance(param: T): R
def concat(s1: R, s2: R): R
}
implicit object IntSetBuilder extends SetBuilder[Int, BitSet] {
def empty = BitSet.empty
def buildInstance(param: Int) = BitSet(param)
def concat(s1: BitSet, s2: BitSet) =
s1 ++ s2
}
implicit object StringSetBuilder extends SetBuilder[String, Set[String]] {
def empty = Set.empty[String]
def buildInstance(param: String) = Set(param)
def concat(s1: Set[String], s2: Set[String]) =
s1 ++ s2
}
def buildSetFrom[T,R](params: T*)(implicit builder: SetBuilder[T,R]): R = {
if (params.nonEmpty)
builder.concat(
builder.buildInstance(params.head),
buildSetFrom(params.tail : _*)
)
else
builder.empty
}
scala> buildSetFrom(1,2,3)
res7: scala.collection.immutable.BitSet = BitSet(1, 2, 3)
scala> buildSetFrom("a", "b", "c")
res8: Set[String] = Set(a, b, c)
Scala in general allows for code that is much more generic than C#, without having the need for reified generics.At worst I could see how it could be a trivial implementation detail, but the fact that Scala went out of their way to use tokens and manifests suggests that the functionality is desired. Whether that's provided by the runtime or by the compiler writer is only a difference in effort (or rather, whose effort).
> The big ML-.NET type system mismatches have to do with things like pervasive overloading in .NET making type inference difficult, nothing to do with reified generics
You've hinted at a side-effect, but no, it has to do with subtyping [1], which naturally leads to co/contra-variance [2]. Or to put it bluntly, in a nominal type system that has sub-typing, Hindley-Milner type-inference is not only "difficult" but actually impossible. And because F# had to be interoperable with .NET, then it needed C# generics. Pity, because there's many things that F# misses, like Ocaml functors, structural typing, type-classes, higher-kinded types and the list can continue. And I just love how List.sum<^T> is defined [3] (static member, FTW).
[1] https://en.wikipedia.org/wiki/Subtyping
[2] https://en.wikipedia.org/wiki/Covariance_and_contravariance_...
In any case, it is true that F#'s type systems has concepts that the CLR doesn't natively support, but I don't see how this demonstrates any weaknesses in the CLR or F#. The exact same thing is true of Scala on the JVM, as far as I can tell - how are erased generics an improvement?
What do you think about being able to use Void in Generics? Java's issue of not supporting primitive types pales in comparison to that.
Also, while reified generics and structs are fine, most of the optimizations one would reasonably suspect to be supported are just not there. Some time ago, it was still faster to pass value types by reference ... that's just embarrassing. Maybe RyuJIT does better here?