How have people faired with Scala integration with Java libraries? When Scala first came out, I liked the idea. If I wanted to use X library, great, I can. As I pondered it more, this seemed terrible. Say I hug the functional side of Scala. I know what I'm doing. Then I hire a Jr Dev. She comes from the world of Java/Python where functional is no as big of thing (keeping in mind that while Python does support, to a degree, functional, many use it as a procedural/OO language in school). Suddenly I have to worry about the Jr Dev doing silly things like introducing mutable Java objects into functional code. Side effects could start to show at odd times, which makes debugging terrible in a production environment.
All that said, how have others dealt with this issue? Did you just not work directly with Java libraries? Did you use the OO side as a Better Java?
There are many answers, often related to company size and interest in teaching. Some large bay area companies think that training people into a FP style of Scala is too expensive/hard to hire for, and end up using it as a nicer Java. Smaller companies that do not hire 100 people to work in Scala every year just bite the bullet, expect FP, and end up wrapping a large majority of Java libraries with FP abstractions, some thin, some quite big.
I prefer an intermediate solution when I can get away with it: Localize the mutable Java objects as much as possible, and just make sure that I don't leave a team/teammate that has little Scala experience all alone for a while. This often leads to styles that might be frowned upon by both camps of programming, but in my experience, dropping to imperative code when FP solutions are harder to optimize, while making sure that mutability is well contained and doesn't cross interfaces is Scala's happy place. Depending on the work to be done, each codebase can be pretty FP heavy, or be mostly imperative with an FP facade.
The real trick with Scala is really library design though: It's very easy to make a new library that has dozens of new concepts and is hard to learn and use, all while exposing things like Shapeless HLists to the outside world, while libraries that are easier to consume and don't crush compilation times through type magic are often tougher on the author, leading to more code generation and macros. Most library authors know so much Scala that they don't realize that just using their library well incurs in quite the mental cost to new developers.
I find that once you're working in immutable/pure style it's worth having an explicit boundary between Scala and Java, a class that exists only to wrap the Java thing you're using, and really it's pretty easy to do so - Java-style code sticks out immediately in code review (though you can implement rules to flag it if you really need to).
I've done all of these approaches in various projects - using Scala just as a better Java, with Java-style code, using Java libraries, then writing code that was in a more immutable style that used wrappers around Java libraries, then writing very pure (i.e. no unmanaged effects) code that either used scala libraries, or used Java libraries only in an interpreter for a monad. All of them work. Mixing mutable objects and pure functional style is never going to go well, and that's as true in Python-only projects (say) as it is in Scala/Java hybrid projects; the language interop doesn't leave you any worse off than you were without it, if that makes sense.
> How have people faired with Scala integration with Java libraries?
It's useful because the JVM ecosystem is much larger than the Scala ecosystem. There's almost always a library for your purpose. If it isn't as idiomatic Scala as you'd want you can often easy create a small wrapper.
> Suddenly I have to worry about the Jr Dev doing silly things like introducing mutable Java objects into functional code.
Code reviews. Let developers peer-review each other's code changes and share knowledge about the functional programming practices used in the codebase. This is not a technical problem and has nothing to do with Scala.
Language design can discourage those bad practices and lessen the workload of code reviews.
Catching bad practices and anti-patterns in code review sounds fine on paper, but I'm sure we've all been in the situation where there simply isn't enough time in the day to do intensive code reviews while still maintaining the pace needed for delivery.
I’ve programmed in Scala most days for the past 3 years, we use plenty of Java libraries, and it works well. Generally it’s as simple as a thin wrapper around the library, that converts mutable data classes to immutable versions (or vice versa), and wraps blocking methods in futures. Sometimes it’s more complex than that, but when I’m reaching for a Java lib, normally it’s just for a few methods that are easily wrapped.
Most Java libraries that would cause issues due to blocking or side effects are covered by the big Scala frameworks like Play/Akka or the large healthy ecosystem of alternatives such as those from Typelevel, 47Degs and many others. If I do need to pull in a Java library it's usually used for something minor and without side effects. On occasion I've had to write small wrappers around blocking or mutable Java API's but it's no big deal. wrt to junior devs they generally write code based on established patterns and we review everything in detail.
When interacting with a Java library, I use scala.collection.JavaConversions to convert any Java structures to the equivalent Scala collection. Once I'm done operating on the collection (map, filter, etc.), I convert it back to Java.
You should be using scala.collection.JavaConverters instead, as it makes the conversion explicit (by adding a ".asScala"/".asJava" method to collections).
Implicit conversions (i.e. where a type is silently converted to another type) is dangerous and can lead to very surprising problems.
All that said, how have others dealt with this issue? Did you just not work directly with Java libraries? Did you use the OO side as a Better Java?