Hacker News new | ask | show | jobs
by timclark 4082 days ago
In my opinion (and I have worked on large scale development in Scala in the past) it is just unnecessarily complicated.

Random annoyances off the top of my head - you can't necessarily understand an isolated function unless you know what implicits are being used, crazy overuse of operator overloading and slow compilation times (this has improved over the years).

You don't have to learn Scala, you could learn Clojure, F#, OCaml or Haskell. They would all teach you interesting aspects of programming and then you could come back and examine Scala with a broader perspective.

4 comments

+1 Implicits. We put very strict limits on use of implcits. They make code extremely difficult to reason about, but can also be incredibly dangerous. I once stumbled upon an implicit cast of Int to Float... Oh, my.
Is there any linters available for IDE's to ensure conformance with a vanilla ruleset of scala? If that existed, scala would be able to shape itself up nicely.
Their are linters available for scala (e.g. wartremover). Also, the Scala compiler supports a number of flags to warn you if your code is using some of Scala's 'more questionable' features. You can even tell the compiler to fail if any of these warnings occur. A list of useful flags can be found at https://tpolecat.github.io/2014/04/11/scalac-flags.html.

You might also want to look at this excellent talk titled 'Toward a Safer Scala' at https://docs.google.com/presentation/d/1tCmphnyP3F5WUtd1iNLu... that recommends a number of best practices that can be followed using Scala.

If you're using sbt, I put together a giter8 template for scala/sbt projects that follows these best practice recommendations at https://github.com/hohonuuli/basicscala.g8

http://www.scalastyle.org/

There should be a linter for whatever IDE you happen to be using.

Any modern scala IDE highlights implicit conversions with a green underline, which I find is plenty to make them readable.
> crazy overuse of operator overloading

F# might not be the best place to go then:

http://stackoverflow.com/questions/2210854/can-you-define-yo...

https://msdn.microsoft.com/en-us/library/dd233204.aspx

Most languages have similar capabilities. E.g. in Java you can define a method called ★★★ if you want (edit: this specific example doesn't seem to work, but certainly non-ascii method names are possible). The difference is cultural; Java libraries generally wouldn't define such a method, while certain Scala libraries might.
FParsec is a port of a Haskell library, so not really reflective of F# culture.
Agreed that implicits were one of the critical things that caused me to move away from Scala. I really couldn't justify in my head the use of such a thing.
The one case I can make for implicit conversions (implicit parameters are brilliant and useful and not normally what people complain about) is the spray-routing DSL, e.g. https://github.com/spray/spray/blob/master/examples/spray-ro... . What would be a separate config file in any other framework is instead ordinary Scala code following the rules of ordinary Scala, which is wonderful - you can factor out and reuse common parts of your routing really easily, because it's all just code.
That actually sounds like you encountered code that shouldn't have been or you had people using Scalaz (which has weird operators taken from Haskell, looking at you <*>.)
For those who don't understand: Scalaz is an additional layer of syntax and tricks on top of what is already there. It seems to have quite a lot of power!

    implicit val option = new Traverse[Option] with MonadPlus[Option] {
    def point[A](a: => A) = Some(a)
    def bind[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa flatMap f
    override def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa map f
    def traverseImpl[F[_], A, B](fa: Option[A])(f: A => F[B])(implicit F: Applicative[F]) =
      fa map (a => F.map(f(a))(Some(_): Option[B])) getOrElse F.point(None)
    def empty[A]: Option[A] = None
    def plus[A](a: Option[A], b: => Option[A]) = a orElse b
    def foldR[A, B](fa: Option[A], z: B)(f: (A) => (=> B) => B): B = fa match {
      case Some(a) => f(a)(z)
      case None => z
    }
  }
Excerpt from https://github.com/scalaz/scalaz#type-class-instance-definit....
Looks pretty readable and reasonable.
That part is fine. The trouble with Scalaz is it adds a bunch of extra operators (that is, methods - the distinction doesn't exist in Scala) like |+|, \*> and >=>.
Scalaz is evil. Some of the operators are even non-ASCII.

Anyway, scala needs less weird operators, not more. Looking at you, parser combinator library.