Although we use strongly type language, we often write
Stringly Typed code or rely too much on base value types like
Relying Too Much on Base Value Types
The Bad and The Ugly
- Typical case class with base value types and String.
Use Value Classes and ADTs
Scala has a good solution for the issue from relying too much on base value types. That is Value Class. So a new type can be defined without any runtime-cost as there is only internal type but no wrapper type after the code gets compiled.
Boolean, it is much better to use ADTs than just
Boolean. In the case class example above, the field
isActive can be re-written as an ADT.
So a possible solution for the first issue might be
Better - Use
In Scala 3 (currently Dotty), it's a language feature called
- Scala 2 - newtype
- Scala 2 - value class
- Scala 3
When creating a newtype for primitive types and you want them to be primitive types like
double instead of boxed-primitive like
Double in runtime, use
The Bad and The Ugly
Throwing Stringly-typed Exception
- The ugly Stringly-typed error handling
More Types for Error Handling
Throwing an exception is bad as you can't even guess how many cases may throw exceptions so it is so hard to reason about. It would be good if a total function can be written so that you don't need to worry about the exception. Yet if it's not possible, instead of writting a partial function and let an exception be thrown, use more types to handle it properly.
- Total Function: A function defined for all possible values for the input type (i.e. for all of the domain).
- Partial Function: A function defined for some values of the input type (i.e. for some of the domain) meaning that there might be some values of the right input type that can't be handled by the function as it's not defined for those values. (e.g.
(a: Int, b: Int) => a / bwhere
0is an input value for the right type of the second param
byet it is not a valid value for
b(not in the domain) so it throws an
If there is only one case that can fail to get the expected result, use
Option. The one failure case does not necessarily mean it is an error. A good example might be finding an element. Let's say you're looking for a user using user's ID. The user with the given ID may or may not exist.
If there are more than one case that can go wrong, use
Either. So it can be either
Left which is a failure or
Right, a successful result.
Left may contain an error and the it can be defined as an ADT.