Artūras Šlajus
<x11@arturaz.net>
2022
// Bad
case class Person(
firstName: String,
lastName: String
)
val firstName = "John"
val lastName = "Smith"
val person = Person(lastName, firstName)
Scala
// Good
case class FirstName(name: String)
case class LastName(name: String)
case class Person(
firstName: FirstName,
lastName: LastName
)
val firstName = FirstName("John")
val lastName = LastName("Smith")
// Compiler error!
val person = Person(lastName, firstName)
Scala
Volts * Amperes = Watts
case class Email private (email: String)
object Email {
// Smart constructor
def create(s: String): Either[String, Email] = {
if (/* validation passes */) Right(new Email(s))
else Left("error message")
}
}
Scala
case class Volts(v: Double) {
def *(a: Amperes): Watts = Watts(v * a.v)
}
case class Amperes(v: Double) {
def *(v: Volts): Watts = v * this
}
case class Watts(v: Double)
// Fun fact - NASA blew up a rocket because they
// multiplied miles with kilometers.
Scala
https://github.com/WalkerCodeRanger/ExhaustiveMatching
[Closed(new[] {
typeof(Mode.Standard), typeof(Mode.KillBased)
})]
public interface IMode {}
public static class Mode {
public record Standard(t: MatchTime) : IMode {}
public record KillBased(k: Kills) : IMode {}
}
public bool hasFinished(s: GameState, m: IMode) =>
m switch {
Mode.Standard s => /* logic */,
Mode.KillBased k => /* logic */,
_ => ExhaustiveMatch.Failed(m)
};
C#
struct MovementHandledProof {}
MovementHandledProof handleMovement() {
// ...
return new MovementHandled();
}
void handleShooting(MovementHandledProof p) {}
public void mainLogic() {
var proof = handleMovement();
handleShooting(proof);
}
C#
trait SafeVector[A] {
case class Index(i: Int)
def indexBy(f: A => Boolean): Option[Index]
def get(i: Int): Option[A]
def get(i: Index): A
}
Scala
def doStuff(
v1: SafeVector[String],
v2: SafeVector[String]
): Unit = {
val maybeIdx1 = v1.indexBy { str =>
str.length == 5
}
maybeIdx1.foreach { idx1 =>
// Type error:
// expected: value of type v2.Index
// found: value of type v1.Index
v2.get(idx1)
}
}
Scala
NonEmpty[A]
, Even[A]
, and other predicates.NonEmpty[Even[Vector[String]]
Even[NonEmpty[Vector[String]]
Vector[String] with NonEmpty with Even
// Potentially failing.
def splitInHalf[A](
v: Vector[A]
): Either[String, (Vector[A], Vector[A])]
// Will always succeed.
def splitInHalf[A](
v: Vector[A] with Even
): (Vector[A], Vector[A])
Scala
https://github.com/fthomas/refined
https://github.com/milessabin/shapeless
switch
statements exhaustivehttps://github.com/WalkerCodeRanger/ExhaustiveMatching
https://github.com/FPCSharpUnity/Unity3D.IncrementalCompiler