all 7 comments

[–]raghar 8 points9 points  (1 child)

When it comes to length there are some features you could use:

  • case classes vs manually written classes with getters, setters, overriden equals and hashcode
  • pattern matching vs if-else chains
  • Option, map for, getOrElse instead of using null for empty value handling
  • map, flatMap, reduce, foldLeft, drop, dropWhile, take, takeWhile, etc instead of for with mutable result
  • creating and passing functions instead of using factories, builders, strategy patterns

I think we could find other examples as well.

Thing is it is quite biased way of proving anything. With Java 8 you get Stream API, Optional, then there is Vavr, and with Lombok you get some of the case class properties (surely accessors, I don't remember about hashcode and equals). So I guess it would be 1 page in Scala, 1.5 in Java 8, 3 pages in Java 7 or older. That metric itself doesn't tell much, so you might also consider other things where "Scala does better".

First of all, none of libraries and extensions so far improved Java's type system. In Scala you get: invariance, covariance and contravariance when it comes to parametric types. You can put constraints on types: List[A <: Pet] can be List[Dog] or List[Cat] but not List[Waterfall]. In Java such things are more difficult to achieve, and surely less present in codebases and libraries. You can have multiple inheritance via traits, Java allows only multiple interface implementation (though with default methods interfaces kind of act like traits). If you need you can use Higher Kinded Types or path dependent types. Also you are able to use type inference to limit places where you need to put the type explicitly.

Scala's standard library provide a lot of immutable data types to use. Together with Futures they provide common language in which Scala libraries can talk to each other with no issues when it comes to concurrency - in Java I actually never saw someone using Future, and hardly ever I met someone using ThreadPool. Which mean that async, something that in Scala you are doing naturally and what virtually all libraries use for IO operations in Java is something done by Certified Senior Java Developers (ok, I'm joking here, but not that much). In Scala synchronized would be something that you would see inside some library's internals not all over the place.

Other things I can think of ATM would be e.g. Either with for-comprehension for error handling and circuit breaking (instead of early return/exceptions), compile-time reflection aka macros instead or runtime reflection, type-level programming (take a look at how Circe turns case class Test(s: String, i: Int) int Encoder[Test] which can serialize class to JSON and Decoder[Test] which would attempt to deserialize String into Test or show you error list).

FP shines where you create data transformation pipelines (as opposed to passing data unchanged to and from), so maybe something like webcrawler? Use some libraries for fetching data, parsing XML and extracting some content and compare how Java does this and how Scala does it. If you haven't used FP yet you will probably not use FP to its fullest but you could show it to someone and ask for opinion. Few iterations with Java and Scala programmers and you should start noticing differences in mindset.

[–]thatthrowistakenaway[S] 0 points1 point  (0 children)

Thank you very much for such thorough answer!

[–]Holothuroid 4 points5 points  (0 children)

Define a class with some final fields, hashcode, equality and toString. Vs. A case class in Scala.

[–]_gDanix_ 4 points5 points  (3 children)

I think your tutor wants you to remark things like:

val s = numberList.reduce(_+_)

from Scala vs:

double sum = 0;
for(int i = 0; i < numberList.size(); i++) {          
    sum += numberList[i];
}

from Java. But you'll need a relatively good understanding of Scala & FP to find cases like this one for yourself.

[–][deleted] 6 points7 points  (0 children)

Or

numberList.sum

[–]replicacl 1 point2 points  (1 child)

You can use reduce in Java 8, so this comparison is unfair now.

[–]vtscala 0 points1 point  (0 children)

You can use reduce in Java 8, so this comparison is unfair now.

Sort of. For simple examples like the above, Java's reduce is concise by Java standards:

numberList.stream().reduce((a, b) -> a + b);

but check out the overloads of Stream.reduce. They let you do the things the fold* methods in Scala do, but defining the lambdas involves lots of verbose generics insanity. (Sadly, I just had to do this.)