Last active
March 9, 2021 17:49
-
-
Save makingthematrix/98b2c4e168d2e77648f0bcbc74523e6d to your computer and use it in GitHub Desktop.
Many happy early returns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final case class Foo(str: String) | |
final case class Bar(n: Int) | |
val seq: Seq[Foo] = Seq(Foo("1"), Foo("-3"), Foo("42"), Foo("5"), Foo("0")) | |
def complexConversion(foo: Foo): Bar = Bar(foo.str.toInt) | |
def complexValidation(bar: Bar): Boolean = bar.n == 42 | |
// 1. the Java-like version | |
def findFirstValidBar1(seq: Seq[Foo]): Option[Bar] = { | |
for (foo <- seq) { | |
val bar = complexConversion(foo) | |
if (complexValidation(bar)) return Some(bar) | |
} | |
None | |
} | |
findFirstValidBar1(seq) | |
// 2. find + map | |
def findFirstValidBar2(seq: Seq[Foo]): Option[Bar] = | |
seq.find(foo => complexValidation(complexConversion(foo))) | |
.map(complexConversion) | |
findFirstValidBar2(seq) | |
// 3. collectFirst | |
def findFirstValidBar3(seq: Seq[Foo]): Option[Bar] = | |
seq.collectFirst { | |
case foo if complexValidation(complexConversion(foo)) => complexConversion(foo) | |
} | |
findFirstValidBar3(seq) | |
// 4. unapply + collectFirst | |
object ValidBar4 { | |
def unapply(foo: Foo): Option[Bar] = { | |
val bar = complexConversion(foo) | |
if (complexValidation(bar)) Some(bar) else None | |
} | |
} | |
def findFirstValidBar4(seq: Seq[Foo]): Option[Bar] = | |
seq.collectFirst { | |
case ValidBar4(bar) => bar | |
} | |
findFirstValidBar4(seq) | |
def safeComplexConversion(foo: Foo): Option[Bar] = foo.str.toIntOption.map(Bar(_)) | |
// if you use don't use Scala 2.13 you need Try(foo.str.toInt).toOption | |
val unsafeSeq: Seq[Foo] = Seq(Foo("1"), Foo("boom!"), Foo("42"), Foo("5"), Foo("0")) | |
// 5. Safe Java-like | |
def findFirstValidBar5(seq: Seq[Foo]): Option[Bar] = { | |
for (foo <- seq) | |
safeComplexConversion(foo) match { | |
case Some(bar) if complexValidation(bar) => return Some(bar) | |
case _ => | |
} | |
None | |
} | |
findFirstValidBar5(unsafeSeq) | |
// 6. Safe unapply + collectFirst | |
object ValidBar6 { | |
def unapply(foo: Foo): Option[Bar] = | |
safeComplexConversion(foo).find(complexValidation) | |
} | |
def findFirstValidBar6(seq: Seq[Foo]): Option[Bar] = | |
seq.collectFirst { | |
case ValidBar6(bar) => bar | |
} | |
findFirstValidBar6(unsafeSeq) | |
// 7. Extracted trait | |
// one such trait for the whole codebase | |
trait Deconstruct[From, To] { | |
def convert(from: From): Option[To] | |
def validate(to: To): Boolean | |
def unapply(from: From): Option[To] = convert(from).find(validate) | |
} | |
// one for each implementation of convert and validate | |
object ValidBar7 extends Deconstruct[Foo, Bar] { | |
override def convert(foo: Foo): Option[Bar] = foo.str.toIntOption.map(Bar(_)) | |
override def validate(bar: Bar): Boolean = bar.n == 42 | |
} | |
// for each use | |
def findFirstValidBar7(seq: Seq[Foo]): Option[Bar] = | |
seq.collectFirst { | |
case ValidBar7(bar) => bar | |
} | |
findFirstValidBar7(unsafeSeq) | |
// 8. a lazy iterator | |
def findFirstValidBar8(seq: Seq[Foo]): Option[Bar] = | |
seq.iterator | |
.map(safeComplexConversion) | |
.find(_.exists(complexValidation)) | |
.flatten | |
findFirstValidBar8(unsafeSeq) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment