Typelevel is the Scala community organization behind Cats and Cats Effect, publishing on functional programming in Scala.
HN commenters mention Cats Effect as a way to make async code easier to follow in Scala, alongside ZIO, when discussing Scala's strengths.
Some tips and remarks for starters:
Scala is a quite "deep" language as it's very powerful (actually it's one of the most powerful languages out there). That can be "overwhelming" to someone just starting out I guess. But regardless some FUD written here and there on the interwebs Scala is not a complicated language. At least if you don't make it so.
Scala was made specifically with the intend to teach people programming. From the ground up.
You don't need to understand monads to understand "Hello World", like in Haskell where printing to the console is an "advanced topic" :-). You can't mess up even the most trivial programs with memory leaks and undefined behavior like in C/C++. You can start out with simple, down to earth code without any friction and slowly build up more understanding for more advanced topics as you go. No need to understand "the monkey holding the jungle" and all that at once.
This is something in which Scala is more or less similar to Python or JavaScript. Actually it's even more amenable to people learning programming from the ground up than the former 'cause it has a very simple "evaluation by substitution" model of operation by default. Everything is an expression, and immutable at first, with makes reasoning about programs as easy as putting numbers into math or physics formulas; something that most people practiced in school for many years already!
To have a smooth start with the language I would recommend having a look at `scala-cli`¹ (for a…
If you restrict yourself using scalafix [1](a linter), scalazzi [2](a linter) or wartremover [3](another linter), you can prevent your code from returning `Any`, `AnyRef`, `Nothing`, or `Unit` and prevent yourself from using `Throw` , partial std lib functions,
or `NonUnitStatements` without explicit annotation.
This effectively locks you into writing pure code (you can extend the linter to cover other things like not using `Future` or not using Java libs outside of `MonadError` from cats[4]). The linters operate on typed ASTs at compile time, and have plugins for the most popular scala build tools. Coupled with `-XFatalWarnings', you can guarantee that nothing unexpected happens unless you explicitly pop the escape hatch, for the most part.
You can still bring in external libraries that haven't been compiled with these safties in place, so you aren't completely safe, but if you use ZIO[5]/Typelevel[6] libraries you can be reasonably assured of referentially transparent code in practice.
There are three schools of thought, roughly, in the scala community towards the depth of using the type system and linters to provide guarantees and capabilities, currently:
1) Don't attempt to do this, it makes the barrier to entry to high for Scala juniors. I don't understand this argument - you want to allow runtime footguns you could easily prevent at compile time because the verifiable techniques take time to learn? Why did you even choose to use a typesafe language and pay the…
Kotlin is a cool language, but doesn't do enough to differentiate itself from Java 8.
There are real benefits to picking the mainstream / popular option, which includes tons of documentation, forum discussions, books and developers available immediately for it. So when you go against the mainstream, those alternative tools have to be worth it.
I think Scala got over the worthiness threshold, by exposing one of the best OOP implementations exposed in a static language, sane generics, higher kinded types and implicits which make it possible to encode type-classes, which led to a community emphasizing on functional programming.
I think Kotlin isn't over that threshold. Some people view its thin layer approach to be an advantage. But it either has to evolve in being more than that, or to divorce itself from the JVM, because it is in direct competition with Java 8 otherwise. Evolving to be more than a Java++ goes against its own philosophy. Divorcing itself from the JVM is a work in progress, they also have a Javascript compiler, but the results aren't convincing enough for now.
It's a nice language, but personally I like those with a strong community of functional programmers and libraries. If I'll see http://typelevel.org for Kotlin, I might reconsider.
Here is a quick shortlist of some type inference issues (some bugs, some enhancements, and some fundamental limitations of the language design) that I run into pretty much daily:
1. (Search for "asInstanceOf"): http://typelevel.org/cats/tut/freemonad.html
2. (Finally fixed and will hopefully be released soon - yay!): https://issues.scala-lang.org/browse/SI-2712
3. https://twitter.com/extempore2/status/430456002392391681
4. http://pchiusano.blogspot.com/2011/05/making-most-of-scalas-extremely-limited.html
5. (Anecdotal): Various pattern matching peculiarities.
Compiler bugs: As long as I write code on the happy path and steer clear of scalaz/shapeless/cats, the compiler is pretty well-behaved and I can go months without getting a compiler crash. However, when I add those in and start writing pure functional code with complicated types that hits the intersections of various features (e.g., GADTs, package objects, implicits), I get a few crashes per week related to known bugs.
It works pretty well, and I am not trying to complain too much about all the mileage I get out of Scala and the excellent tooling! Just trying to get the most out of it.
I think I know what you are talking about. In a typical three-tier enterprise application there's no clear separation of concerns between "services" and DAO/Repo... And this is due to how most persistence libraries are designed: they eagerly execute side-effects, this breaks composability due to poor transaction control, so you end up leaking a lot of your business logic into your supposedly persistence layer.
Take a look at Scala's doobie[1]. Any doobie operation returns a `ConnectionIO`, which is only a description of an operation (free monad). With a proper doobie usage the DAO layer is an algebra of possible persistence-related operations, and the service layer implements business logic by combining primitive ConnectionIOs and interpreting them with full control of transaction boundaries.
[1] https://typelevel.org/doobie/index.html
I would use Scala. I like FP and Scala comes with some awesome libraries for concurrent/async programming like Cats Effect or ZIO. Good choice for creating modern style micro-services to be run in the cloud (or even macro-services, Scala has a powerful module system, so it's made to handle large codebases).
https://typelevel.org/cats-effect/
https://zio.dev/
The language, the community and customs are great. You don't have to worry about nulls, things are immutable by default, domain modelling with ADTs and patter matching is pure joy.
The tooling available is from good to great and Scala is big enough that there are good libraries for typical if not vast majority of stuff and Java libs as a reliable fallback.