Skip to content

Instantly share code, notes, and snippets.

@dwijnand
Last active July 1, 2016 18:09
Show Gist options
  • Save dwijnand/2874b497654ed4867528d1728bcb14a7 to your computer and use it in GitHub Desktop.
Save dwijnand/2874b497654ed4867528d1728bcb14a7 to your computer and use it in GitHub Desktop.
package p
/** Decodes strings into Ts */
trait Decoder[T] {
def decode(s: String): Either[String, T]
}
object Decoder {
def apply[T](f: String => Either[String, T]): Decoder[T] =
new Decoder[T] { def decode(s: String) = f(s) }
}
final class PosInt private (val x: Int)
object PosInt extends PosInt0 {
def apply(x: Int): Either[String, PosInt] =
if (x > 0) Right(new PosInt(x)) else Left("not a positive int")
}
// Not in PosInt so that the private constructor isn't reachable and apply must be used instead
abstract class PosInt0 { self: PosInt.type =>
def apply(x: Int): Either[String, PosInt]
// final so it can't be redefined in PosInt.type
final implicit val posIntDecoder: Decoder[PosInt] =
Decoder(s => try apply(s.toInt) catch { case _: java.lang.NumberFormatException => Left("not an int") })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment