Hello colleagues.
Not so long ago we finished the
book of Oder, Sp n and Venners on Scala 2.12. After all, Scala 3 is still far away.
The author of today's article is Adam Worsky, co-founder of SoftwareMill and an experienced Scala developer. He got an interesting summary of the strengths of the modern language Scala, which we bring to your attention.
')
After the
plenary lecture of Martin Oderski on ScalaDays, where he outlined plans for Scala 3 and the
plenary lecture of John de Goes at the Scalapeño conference about the future of
Scala , lively discussions continue in
the Scala community . Apart from the discussion of these plenary speeches, numerous discussions go on twitter, in the Slack communities, and also on reddit (see for example
1 ,
2 ).
That is the question!All this is very interesting and informative for professionals already working in the Scala ecosystem. However, much of the controversy is associated with various intuitively perceived or actual deficiencies of Scala as a language. These moments can scare people away, causing them questions: “Why do I need to use Scala at all?”, “What if this is a dead end?”, “Will Scala 3 repeat the success of Python 3?”, Etc. As in most discussions, attention is drawn to the weakest and most emotional theses, and this debate is no exception.
Therefore, we
take a step back : why would you even need the Scala language? What are the technical and business reasons for working with these languages?
Project AreaTo begin with, the Scala language is especially good for certain subject areas (but not for everyone!). The most important advantage of Scala is the
flexibility in defining abstractions . At your disposal - a number of simple "bricks" for this; sometimes defining an abstraction is as simple as using a class, methods, and lambda expressions. Sometimes you have to use an implicit parameter or extension method; in rare cases, it only remains to resort to macros. However,
there are options .
Thus, Scala is perfect for you if you need to
navigate a complex subject area . For example, we can talk about distributed or competitive programming. Concurrency is very difficult, and Scala has a number of libraries that simplify this task by building abstractions. To do this, there are two main approaches: actor, implemented with the help of
Akka , and in the spirit of FP, presented by
Monix /
cats-effect and
Scalaz /
ZIO (if you wanted to read more about comparing these tools - I wrote a
series of articles on this subject ).
However, of course, we can talk about other subject areas. Scala's capabilities also allow you to take the modeling of typical business applications to a new level. But in this case we are talking about the complexity of a different order. In the case of distributed systems, we are faced with technical difficulty. When programming business logic in applications, we are already talking about the complexity of the subject area as such. For example, the book “
Functional and reactive domain modeling ” by Debasish Ghosh explains how to combine DDD with functional and reactive programming.
Language difficultyNote: talking about Scala, everyone likes to emphasize the breadth of the possibilities of this language, emphasizing that it is because of such a versatility that language is so complicated. This is not entirely true.
As mentioned above, Scala has a number of basic constructs from which abstractions can be assembled. However, all of them can be
combined with each other, so that the language and acquires such flexibility. Most of the innovative projects that you may come across are reduced to some combination of higher order types, implicit parameters, and subtyping.
Thus, with a relatively small number of basic features (Scala grammar is simpler than Kotlin, Java or Swift!) - which, in turn, facilitates learning - the options for combinations are much more numerous.
Is it too wide a choice? I do not think. The programmer, as a competent and responsible professional, is more than able to choose the best option to solve a specific task. For more on this, see the article “
Scala Simple Stack ”.
Java, only betterNow they say a lot that
Kotlin ousted Scala as “like Java, only better.” But I think that
Scala, and not Kotlin , still deserves this title. There are two main reasons for this:
First,
immutability in the Scala language is paramount . This is due to the nature of Scala itself: it is convenient to write code on it first of all with the help of immutable data. Such data include, in particular:
val
(as first-class units),
case
classes, higher-order functions, etc. But the point is how the standard library of the Scala language is designed and written; All data structures used by default are immutable. Thanks to immutability, a number of things are simplified, especially in our world of high competition, where exactly those languages ​​where immutability is preferred win.
Secondly, Scala supports
type constructors, higher order types, and class types (declared implicitly), which greatly simplifies working with wrapping / container types, for example, with
Promise
,
Future
or
Task
. Such wrappers prevail when programming in an asynchronous or reactive style, and the presence of language constructs that simplify work with, say, such a code base where
Future
is actively used is another argument in favor of Scala.
What are class types? Their role is approximately the same as that of design patterns in Java, however, they are more flexible and easy to use as soon as you get a good understanding of their meaning. There are several excellent guides for this, for example,
1 ,
2 .
What about type constructors? These are types such as
Future
or
Option
that serve as “containers” or “wrappers” for other types. So, you can have
Option[String]
or
Future[Int]
. Higher order types allow you to write code that abstracts any wrapper. See for example.
1 ,
2 .
Suddenly you wonder, why bother to resort to the
Future
/
Task
? The point is not only that most high-performance “reactive” calculations with minimal delays are performed using asynchronous I / O, for which such constructions are simply asked for. Other reasons are given in this
discussion on reddit and in my article “
Why bother with wrappers? ".
Working in a predominantly immutable environment, as well as the ability to conveniently handle such constructs as
Future
,
Promise
or
Task
(and abstract them!) Radically transforms your code. At first glance, this may not be obvious: if you have Java or Ruby experience behind you, you will not be able to recognize these aspects of Scala right away. But, even from an educational point of view, it is useful to understand how the “functional” approach works and, more importantly, why it can turn out to be a
very worthy alternative .
Naturally, both Scala and Kotlin have a number of general advantages over Java, for example:
- More compact syntax
- Less stereotypical code
- More saturated type system
- Lack of language ballast
At the same time, both languages ​​provide access to the ecosystem of JVM libraries and frameworks.
The richer the type system (in Scala it is richer than in Kotlin, and in Kotlin it is richer than in Java), the more verification work is performed by the compiler, and not by man. It is for this purpose that computers were created: to perform boring, routine repetitive tasks. Testing the applicability of types is definitely one of these tasks.
At the same time, a rich type system is useful not only when
writing code , but also, to a much greater extent, when
reading code . When it is easy for you to orient yourself in the code base, to understand what it does, and, moreover, it’s not scary (or not so scary) to take on its
refactoring , this very positively characterizes the language from both a technical and an applied point of view.
OP vs OOPAnother question often raised in such discussions is whether Scala should continue to adhere to the synthesis of OOP and AF, or develop along a purely functional path. I am a
supporter of synthesis , especially because the OP and OOP, in my opinion, are not alternative approaches, but complementary ones.
FP is
programming using functions , though not any, but referentially transparent (see this
answer to reddit in an earlier thread, where referential transparency is perfectly explained). In OOP, communication with objects is organized using “messages” or, in our terminology, calls to virtual methods. There is not a single reason why these two approaches could not coexist, and Scala has already demonstrated this!
In a
tweet about the advantages of Scala, John de Gous mentions some features of OOP that are useful in a purely functional approach, in particular,
first-class modules (obtained by composition of objects),
point syntax (calling methods in objects), and type
classes /
instances as first-class constructs . All these are elements of a successful combination of two paradigms. Maybe some others are just around the corner?
The project of "synthesis" is not finished yet, there is definitely a field for discussion. One of the unfinished aspects is the proposed syntax for extension methods, which should replace much more confused implicit conversions. The other is optimization of the syntax of type classes;
A suggestion made on this occasion some time ago is clearly raw and does not cover some of the most common uses of monads in Scala. Some proposals are better, others require refinement, but it’s good that they are coming in and there are discussions about them; thanks to them, the language lives and, ultimately, it fixes the best solution.
Scala 3Scala 3 will be released in two years. A number of interesting features will appear in it, in particular, opaque types, type parameters, a new approach related to metaprogramming, union types and intersections, implicit function types - these are just a few examples. Of course, there is a (legitimate) concern about migration.
It is already known that a special tool will be presented for the
automatic migration of code from Scala 2 to Scala 3 using
scalafix . Since Scala is a statically typed language, this problem is solvable on a large scale and much simpler than, for example, in Python. But, of course, there is no magic here: even if this tool provides 99% of the correct coverage of the code, 1% of the most problematic cases will remain. Since magic cannot be expected, the migration of these fragments will need to be done manually.
These are the costs of working with an actively developing language: you get the latest features, but some of them turn out to be not so good and need to be improved. Even so, the proposed changes are not revolutionary. Scala 3 is very similar to Scala 2, no major paradigm changes are foreseen.
The fact that the Scala team is serious about migration is encouraging. While previously migrating between older versions of Scala (for example, from 2.8 to 2.9) was rather cumbersome, recent migrations were much better. There are three main parties involved: EPFL,
ScalaCenter and
Lightbend all (often together) work to facilitate migration. For example, there is a binary compatible
MIMA tool, and numerous new libraries are constantly being created in the community to ensure convenient work with new versions of Scala.
Finally, the TASTY tool, which has not yet been completed (which, accordingly, cannot be assessed yet), should ensure the use of binary files from Scala 2 to Scala 3.
So why use Scala?So, what are the reasons to stay at Scala, if we consider this language from a business point of view? All of the above technical advantages are directly useful for business. When you have a language in which you can write complex code with fewer bugs, then you are provided with minimal delays and satisfied users. If you begin to write powerful, practically non-slip competitive applications on Scala, for which Scala has special tools, this will result in a serious benefit for your company.
In addition, do not forget about
Spark , the leading platform for
distributed data analysis . Scala is used not only to implement Spark as such, but also to determine the calculations themselves. Here you have another data science-oriented abstraction that hides a complex computational model.
SummaryOf course, there are problems in Scala, but where are they not? The reason for optimism lies in the fact that many people who use Scala daily, are actively working to
improve the tools , libraries and the language itself. I can assume that they continue to work with Scala precisely because, for all the existing flaws, not a single language is so well suited to their subject area.
Scala allows you to develop your programming style, no matter what language you used to do: Java, Ruby, or just try yourself in programming. There is no unique winning approach to Scala; one can follow either the more
imperative approach of Akka, or the more
functional approach of Cats and Scalaz.
This is where the problem can be perceived: there are factions in the Scala community that adhere to the “reactive”, “synthetic” OO / OP approach and pure AF. However, this is actually a huge advantage. Due to this diversity, discussions are held, many different opinions are expressed from different points of view. In this, in turn, it is perfectly possible to learn non-standard problem solving and enrich your own tools.
Whatever path you choose in Scala, you will be supported by an impressive community of colleagues engaged in the development of libraries and frameworks; these people are always ready to help and discuss emerging ideas.