Skip to content

Instantly share code, notes, and snippets.

@noahlz
Last active August 29, 2015 14:00
Show Gist options
  • Save noahlz/11330593 to your computer and use it in GitHub Desktop.
Save noahlz/11330593 to your computer and use it in GitHub Desktop.
A friend asked what I thought about Scala after coding it for about 6 months. Here's my reply:

Scala can be a little obtuse. Yesterday I encountered something like this:

def foo(bar: Bar): Option[Bazz => Buzz => Blah]

It's a function that takes Bar and returns an Option boxing a function that takes a Buzz and returns a Blah. I think some clarifying parenthesis are in order, and probably should be required by the compiler.

When you see something like this:

val foo = someFunction(1)(2)

You don't know if foo is a function has two parameters (and can be partially applied), or if it is a function that returns a function that you are immediately invoking. There is just no way to know from looking at it. It could be either:

def someFunction(a: Int)(b: Int) = { a + b }

or

def someFunction(a: Int) = { (b: Int) => a + b }

There's this one, which many folks new to the language find confusing - you might think the { ... } is a block, but actually it's a statement where there last expression needs to be the function executed by map.

List(1,2,3).map { println("In map"); x => x + 1 }
// In map
//=> res5: List[Int] = List(2, 3, 4)

"for/yield" comprehensions are sold as this awesome language feature until you try to mix Option and traversables , at which point you get cryptic compiler errors that reveal for/yield is really a macro emitting map / filter code that is subsequently compiled.

for { a <- Some(1); b <- List(1) } yield (a, b)
// <console>:8: error: type mismatch;
// found   : List[(Int, Int)]
//  required: Option[?]
//               for { a <- Some(1); b <- List(1) } yield (a, b)

See: http://stackoverflow.com/questions/4719592/type-mismatch-on-scala-for-comprehension

Underscores in scala are completely silly in the ways that they are overloaded, and the language could probably do without them. Yesterday, I learned about the following:

def blah = (_: Int) + (_: Int)
// blah: (Int, Int) => Int

blah(1,2)
// res10: Int = 3

I'm not sure how this makes the code more readable. You saved some typing / thought by not naming those parameters, but to my eyes it looks like they are the same parameter doubled, not two distinct positional parameters.

blah(1)
// <console>:9: error: not enough arguments for method apply: (v1: Int, v2: Int)Int in trait Function2.
// Unspecified value parameter v2.
//               blah(1)
//                  ^

Poor coding style / type abuse can make for some really silly looking code. Scala doesn't help prevent that. See:

Scala is like C++ - in the right hands, it's a fine language, but not unlike C++ templates it can be misused to make clever code that is a challenge to read and has ridiculous compiler errors.

Anyway, other than these occasional annoyances I rather like coding in Scala - at least it's not Java!

@ericacm
Copy link

ericacm commented Apr 27, 2014

I didn't know that you could do List(1,2,3).map { println("in map"); x => x + 1 }, that's interesting.

I look at it as a block like:

scala> List(1,2,3).map { x =>
     | println("in map")
     | x + 1
     | // etc
     | }
in map
in map
in map
res3: List[Int] = List(2, 3, 4)

Re: for, it arguably should have been called do a la Haskell, and then there could be an optimized Java-style for loop. I've been doing Scala for close to 4 years now and I still have to think when I am writing a for expression whether or not all of the generators are compatible.
Technically it's not a macro, it's compiler "sugar" - macros are a very recent thing. A detailed explanation of the desugaring is: http://www.artima.com/pins1ed/for-expressions-revisited.html.

Speaking of Haskell, I learned a lot, ironically, about Scala reading Learn You a Haskell for Great Good!.

def blah = (_: Int) + (_: Int)
// blah: (Int, Int) => Int

This is a method that returns a function that takes two parameters, not a method that takes two params. That's a syntax that I hadn't seen before either. I would normally do:

scala> def blah = (x: Int, y: Int) => x + y
blah: (Int, Int) => Int

scala> blah(1,2)
res4: Int = 3

Personally I like the underscores - I think they're pretty intuitive in the places where they're used. Don't know if you've seen http://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala.

Though when using underscores in function literals you have to be careful: http://stackoverflow.com/questions/16498543/why-does-this-wildcarded-function-tells-me-it-has-the-wrong-number-of-parameters

@noahlz
Copy link
Author

noahlz commented May 13, 2014

I generally eye any scala expression that uses underscores with suspicion. That syntax is way too overloaded.

I also prefer def foo = (x: Int, y: Int) => x + y and don't quite understand why anyone would prefer the (_: Int) version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment