Importance of types
Pathological states are unreachable; the state space of the application simply does not include them.
Scala 3 has some new keywords that help metaprogramming. Here are some notes I made as I try to grok them.
New Scala3 Keywords
The inline modifier "tells the compiler that it should inline any invocation of this method at compile-time. If it's not possible, compiler will fail the compilation." Note that the compiler will complain with inline match can only be used in an inline method if you try to put it in a normal match clause.
The inline keyword will partially act like the Scala 2 or C/C++ version of the keyword if the expression is too complex to evaluate at runtime. That is, it will stick the code in at compile time and let it evaluate at runtime. If you don't want this partial evaluation, "you can tell the compiler to avoid complex expression as parameter. This is done by using an inline if" [Scalac blog]. So, by using a def and an if that are both inlined you could, for example have all debug statements removed at compile time.
Note, the parameters to a function can also be inlined.
"erasedValue comes from compiletime package. It's usually used in tandem with inline match. It allows us to match on the expression type, but we cannot access extracted value as that code is executed at compile-time
"constValue comes from compiletime too. It returns the value of a singleton type."
Note that "in Scala 3 you must use a lower-case identifier for a type being extracted from a pattern match." [MichaĆ Sitko's excellent blog post]
The keyword using appears to be the Scala 3 equivalent of implicit in Scala 2. For compilation to succeed, every time you see a using there must be a corresponding given that satisfies its demands.
The keyword with is a synonym for the equals operator. Quoting the Scala Book, this SO answer says:
Because it is common to define an anonymous instance of a trait or class to the right of the equals sign when declaring an alias given, Scala offers a shorthand syntax that replaces the equals sign and the "new ClassName" portion of the alias given with just the keyword with.
If we define the natural numbers as:
trait Nat
class _0 extends Nat
class Succ[A <: Nat] extends Nat
trait <[A <: Nat, B <: Nat]
given basic[B <: Nat]: <[_0, Succ[B]] with {}
given inductive[A <: Nat, B <: Nat](using lt: <[A, B]): <[Succ[A], Succ[B]] with {}
(From RockTheJVM)
So, that inductive function allows compilation if it is satisfied in a (potentially) recursive manner until we reach basic. Having these axioms in the ether, we can compile this:
type _1 = Succ[_0]
type _2 = Succ[_1] // Succ[Succ[_0]]
type _3 = Succ[_2] // Succ[Succ[Succ[_0]]]
type _4 = Succ[_3] // Succ[Succ[Succ[Succ[_0]]]]
...
I hope to build on this to make data engineer pipelines easier to debug. I'll expand on this idea in a future post as this has become long enough.
No comments:
Post a Comment