I have a trait
trait A {
def doSomething(a: Seq[Int]): Seq[String] = {
a.map {
case AA(s) => s // want to use unapply defined in trait (this(AA) not allowed)
case _ => "idc"
}
}
def unapply(a: Int): Option[String] = getString(a)
def getString(a: Int): Option[String] = {
a match {
case 1 => Some("one")
case 2 => Some("two")
case _ => None
}
}
}
object AA extends A
object AA2 extends A {
override def getString(a: Int): Option[String] = {
super.getString(a).orElse{
a match {
case 3 => Some("three")
case 4 => Some("four")
case _ => None
}
}
}
}
object MyClass {
def main(args: Array[String]) {
println(AA.doSomething(Seq(1,2,3,4,5))); // Output: List(one, two, idc, idc, idc)
println(AA2.doSomething(Seq(1,2,3,4,5))); // Expect Output: List(one, two, three, four, idc) but get List(one, two, idc, idc, idc)
}
}
The problem here is I can't use the unapply defined in the trait without creating an extractor object.
I would like to override the getString method in different objects using this trait.
You can use a self type to reference yourself.
trait A { self =>
final def doSomething(a: Seq[Int]): Seq[String] =
a.map {
case self(s) => s
case _ => "idc"
}
final def unapply(a: Int): Option[String] =
getString(a)
def getString(a: Int): Option[String] =
a match {
case 1 => Some("one")
case 2 => Some("two")
case _ => None
}
}
Which works as expected.
Code running here.
One solution I used was
trait A {
def doSomething(a: Seq[Int]): Seq[String] = {
a.map {
case Extractor(s) => s
case _ => "idc"
}
}
object Extractor {
def unapply(a: Int): Option[String] = getString(a)
}
def getString(a: Int): Option[String] = {
a match {
case 1 => Some("one")
case 2 => Some("two")
case _ => None
}
}
}
object AA extends A
object AA2 extends A {
override def getString(a: Int): Option[String] = {
super.getString(a).orElse{
a match {
case 3 => Some("three")
case 4 => Some("four")
case _ => None
}
}
}
}
object MyClass {
def main(args: Array[String]) {
println(AA.doSomething(Seq(1,2,3,4,5))); // Output: List(one, two, idc, idc, idc)
println(AA2.doSomething(Seq(1,2,3,4,5))); // Output: List(one, two, three, four, idc)
}
}
Related
I am trying to extend class with overloaded method so I can instantiate it and pass different number of argument but keep common type of Foo and Bar. How can I make my code runnable?
class GenericClass {
def run(x: Int): Unit
def run(x: Int, y: Int): Unit
}
class Foo extends GenericClass {
def run(x: Int): Unit
}
class Bar extends GenericClass {
def run(x: Int, y: Int)
}
def getRun(hello: String) = {
hello match {
case "foo" => new Foo
case "bar" => new Bar
}
}
def execIt(runType: String) = {
case "foo" => getRun(runType).run(2)
case "bar" => getRun(runType).run(2, 3)
}
execIt("foo")
You can try to introduce a type member
trait GenericClass {
type In
def run(x: In): Unit
}
class Foo extends GenericClass {
override type In = Int
override def run(x: Int): Unit = println("Foo#run")
}
class Bar extends GenericClass {
override type In = (Int, Int)
override def run(x: (Int, Int)): Unit = println("Bar#run")
}
def getRun(hello: String) = {
hello match {
case "foo" => new Foo
case "bar" => new Bar
}
}
def execIt(runType: String) = getRun(runType) match {
case foo: Foo => foo.run(2)
case bar: Bar => bar.run(2, 3)
}
execIt("foo") // Foo#run
or a type class
trait GenericClass
class Foo extends GenericClass
class Bar extends GenericClass
trait Run[A <: GenericClass, T] {
def run(a: A, t: T): Unit
}
object Run {
implicit val foo: Run[Foo, Int] = (a, t) => println("Run.foo")
implicit val bar: Run[Bar, (Int, Int)] = (a, t) => println("Run.bar")
}
implicit class RunOps[A <: GenericClass](val a: A) extends AnyVal {
def run[T](t: T)(implicit r: Run[A, T]): Unit = r.run(a, t)
}
def getRun(hello: String) = {
hello match {
case "foo" => new Foo
case "bar" => new Bar
}
}
def execIt(runType: String) = getRun(runType) match {
case foo: Foo => foo.run(2)
case bar: Bar => bar.run(2, 3)
}
execIt("foo") // Run.foo
Please notice that I modified execIt as well.
Also you can keep everything as is and just throw NotImplementedError for methods that aren't needed
trait GenericClass {
def run(x: Int): Unit
def run(x: Int, y: Int): Unit
}
class Foo extends GenericClass {
def run(x: Int): Unit = println("Foo#run")
def run(x: Int, y: Int): Unit = ???
}
class Bar extends GenericClass {
def run(x: Int): Unit = ???
def run(x: Int, y: Int) = println("Bar#run")
}
def getRun(hello: String) = {
hello match {
case "foo" => new Foo
case "bar" => new Bar
}
}
def execIt(runType: String) = runType match {
case "foo" => getRun(runType).run(2)
case "bar" => getRun(runType).run(2, 3)
}
execIt("foo") // Foo#run
although this last option seems to abuse OOP.
When I try to compile the following I get:
"not found: value cons" and "not found: value empty" for the take and drop method definitions.
Somehow the trait doesn't "see" the companion object?
I'm using IntelliJ IDEA, in case that matters.
import scala.annotation.tailrec
object Run extends App {
sealed trait StreamRed[+A] {
def headOption: Option[A] = this match {
case Empty => None
case Cons(h,t) => Some(h())
}
def toList: List[A] = {
#tailrec
def toListRec(stream: StreamRed[A], accumulated: List[A]): List[A] = this match {
case Cons(h,t) => toListRec(t(), h()::accumulated)
case _ => accumulated
}
toListRec(this, List()).reverse
}
def take(n: Int): StreamRed[A] = this match {
case Cons(h, t) if n > 1 => cons(h(), t().take(n - 1))
case Cons(h, _) if n == 1 => cons(h(), empty)
case _ => empty
}
#tailrec
def drop(n: Int): StreamRed[A] = this match {
case Cons(_,t) if n > 0 => t().drop(n-1)
case _ => empty
}
}
case object Empty extends StreamRed[Nothing]
case class Cons[+A](h: () => A, t: () => StreamRed[A]) extends StreamRed[A]
object StreamRed {
def cons[A](hd: => A, tl: => StreamRed[A]): StreamRed[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def empty[A]: StreamRed[A] = Empty
def apply[A](as: A*): StreamRed[A] =
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
}
Companions can see each other's members in the sense that access modifiers are not a problem.
class A {
private def foo: Unit = ()
A.bar
}
object A {
private def bar: Unit = ()
(new A).foo
}
is ok on contrary to
class A {
private def foo: Unit = ()
B.bar
}
object B {
private def bar: Unit = ()
(new A).foo
}
(But if you replace private with private[this] the former won't work either.)
But this doesn't mean that namespaces are imported automatically.
class A {
private def foo: Unit = ()
import A._
bar
}
object A {
private def bar: Unit = ()
val a = new A
import a._
foo
}
is ok on contrary to
class A {
private def foo: Unit = ()
bar
}
object A {
private def bar: Unit = ()
foo
}
Anyway a method has to know its this.
Suppose I am refactoring a function like this:
def check(ox: Option[Int]): Unit = ox match {
case None => throw new Exception("X is missing")
case Some(x) if x < 0 => throw new Exception("X is negative")
case _ => ()
}
I'd like to get rid of the exceptions but I need to keep the check signature and behavior as is, so I'm factoring out a pure implementation -- doCheck:
import scala.util.{Try, Success, Failure}
def doCheck(ox: Option[Int]): Try[Unit] = ???
def check(ox: Option[Int]): Unit = doCheck(ox).get
Now I am implementing doCheck as follows:
def doCheck(ox: Option[Int]): Try[Unit] = for {
x <- ox toTry MissingX()
_ <- (x > 0) toTry NegativeX(x)
} yield ()
Using the following implicits:
implicit class OptionTry[T](o: Option[T]) {
def toTry(e: Exception): Try[T] = o match {
case Some(t) => Success(t)
case None => Failure(e)
}
}
implicit class BoolTry(bool: Boolean) {
def toTry(e: Exception): Try[Unit] = if (bool) Success(Unit) else Failure(e)
}
The implicits certainly add more code. I hope to replace OptionTry with an implicit from scalaz/cats someday and maybe find an analog for BoolTry.
You could refactor with a loan pattern and Try.
def withChecked[T](i: Option[Int])(f: Int => T): Try[T] = i match {
case None => Failure(new java.util.NoSuchElementException())
case Some(p) if p >= 0 => Success(p).map(f)
case _ => Failure(
new IllegalArgumentException(s"negative integer: $i"))
}
Then it can be used as following.
val res1: Try[String] = withChecked(None)(_.toString)
// res1 == Failure(NoSuchElement)
val res2: Try[Int] = withChecked(Some(-1))(identity)
// res2 == Failure(IllegalArgumentException)
def foo(id: Int): MyType = ???
val res3: Try[MyType] = withChecked(Some(2)) { id => foo(id) }
// res3 == Success(MyType)
I would like to do something like this:
implicit class MyString(s: String) {
def getAs[T]: T = {
T match {
case q if q == classOf[Int] => s.toInt
case q if q == classOf[Boolean] => s.toBoolean
}
}
}
This doesn't compile, of course. How do I write this so it does?
Consider this approach:
object Parse {
def parse[T](f:String => Option[T]) = f
implicit val parseInt = parse(s => Try(s.toInt).toOption)
implicit val parseLong = parse(s => Try(s.toLong).toOption)
implicit val parseDouble = parse(s => Try(s.toDouble).toOption)
implicit val parseBoolean = parse(s => Try(s.toBoolean).toOption)
}
implicit class MyString(s:String) {
def getAs[T]()(implicit run: String => Option[T]): Option[T] = run(s)
}
Usage:
def main(args: Array[String]) {
import Parse._
"true".getAs[Boolean].foreach(println)
"12345".getAs[Int].foreach(println)
}
When use classOf for type match, there maybe will have some issues, example:
scala> classOf[List[Int]] == classOf[List[String]]
res17: Boolean = true
scala> typeOf[List[Int]] =:= typeOf[List[String]]
res18: Boolean = false
classOf only store the class information not with generics type
typeOf will store full type information
TypeTags and Manifests
class MyString(s: String) {
def getAs[T](implicit tag: TypeTag[T]): T = {
tag.tpe match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
}
}
}
scala> new MyString("123")
res2: MyString = MyString#7fca02
scala> res6.getAs[Int]
res3: Int = 123
use TypeType tag to get type info, and call getAs with type information.
This is what I have come up with so far:
import reflect.runtime.universe.TypeTag
import scala.reflection.runtime.universe._
implicit class MyString(s: String) {
def getAs[T : TypeTag]: T = {
typeOf[T] match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
case t if t =:= typeOf[Boolean] => s.toBoolean.asInstanceOf[T]
}
}
}
Running with this in REPL:
scala> "32".getAs[Int]
res25: Int = 32
scala> "32".getAs[Boolean]
java.lang.IllegalArgumentException: For input string: "32"
at scala.collection.immutable.StringLike$class.parseBoolean(StringLike.scala:290)
at scala.collection.immutable.StringLike$class.toBoolean(StringLike.scala:260)
at scala.collection.immutable.StringOps.toBoolean(StringOps.scala:30)
at MyString.getAs(<console>:33)
... 43 elided
scala> "false".getAs[Int]
java.lang.NumberFormatException: For input string: "false"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
at scala.collection.immutable.StringOps.toInt(StringOps.scala:30)
at MyString.getAs(<console>:32)
... 43 elided
scala> "false".getAs[Boolean]
res28: Boolean = false
scala> "false".getAs[String]
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
at MyString.getAs(<console>:31)
... 43 elided
Better, I think, would be to return an option[T], and catch any issues such as a type T that isn't catered for, or attempting a cast that will fail. I started mucking around with scala's Try (and its .toOption method), but hit some odd errors so haven't gotten any further with that.
EDIT: just using a simple try-catch, we can get:
implicit class MyString(s: String) {
def getAs[T : TypeTag]: Option[T] = try {
typeOf[T] match {
case t if t =:= typeOf[Int] => Some(s.toInt.asInstanceOf[T])
case t if t =:= typeOf[Boolean] => Some(s.toBoolean.asInstanceOf[T])
}
} catch {
case ex: Exception => None
}
}
Resulting in:
scala> "false".getAs[String]
res30: Option[String] = None
scala> "32".getAs[Boolean]
res31: Option[Boolean] = None
scala> "32".getAs[Int]
res32: Option[Int] = Some(32)
scala> "true".getAs[Boolean]
res33: Option[Boolean] = Some(true)
scala> "true".getAs[Int]
res34: Option[Int] = None
Based on the answers given by #chengpohi and #Shadowlands, this is what I came up with.
object ImplicitsStartingWithS {
implicit class MyString(s: String) {
val str = s.trim
import reflect.runtime.universe.TypeTag
import scala.reflect.runtime.universe._
def getAs[T](implicit tag: TypeTag[T]): Option[T] = {
val value = tag.tpe match {
case t if t =:= typeOf[Int] => str.toIntStr.map(_.toInt)
case t if t =:= typeOf[Long] => str.toIntStr.map(_.toLong)
case t if t =:= typeOf[Float] => str.toNumericStr.map(_.toFloat)
case t if t =:= typeOf[Double] => str.toNumericStr.map(_.toDouble)
case _ => None
}
value.asInstanceOf[Option[T]]
}
def toDecimalStr = "^-*\\d+\\.\\d+$".r.findFirstIn(s)
def toIntStr = "^-*\\d+$".r.findFirstIn(s)
def toNumericStr = {
s.toDecimalStr match {
case Some(decimalStr) => Some(decimalStr)
case None => s.toIntStr
}
}
}
}
This avoids exception handling for faster response.
If come across an interesting case with thunks versus functions in the presence of type Nothing:
object Test {
def apply(thunk: => Any ): String => Any = _ => thunk
def apply(fun: String => Any): String => Any = fun
}
val res0 = Test { println("hello") }
res0("foo") // --> hello
val res1 = Test { x: String => println(s"hello $x") }
res1("foo") // --> hello foo
val res2 = Test { x: String => throw new RuntimeException("ex") }
util.Try(res2("foo")) // --> Failure
val res3 = Test { throw new RuntimeException("ex") } // boom!
Now the tricky bit is the last case. Is it possible to modify the apply method to make Scala choose the thunk version of it, instead of the Function1 version (which is more specific and thus preferred, and Nothing <: Function1[_,_], therefore...)
I tried to come up with low-high priority implicits and magnet pattern, but haven't found a solution yet.
Here's a quick draft of a type-safe approach based on type classes:
object Test {
trait Wrap[A, B] { def apply(a: => A): String => B }
trait LowWrap {
implicit def thunkWrap[A] = new Wrap[A, A] { def apply(a: => A) = _ => a }
}
trait MidWrap extends LowWrap {
implicit def funcWrap[A] = new Wrap[String => A, A] {
def apply(f: => String => A) = f
}
}
object Wrap extends MidWrap {
implicit object nothingWrap extends Wrap[Nothing, Nothing] {
def apply(f: => Nothing) = _ => f
}
}
def apply[A, B](a: => A)(implicit w: Wrap[A, B]) = w(a)
}
And then:
scala> Test { println("hello") }
res0: String => Unit = <function1>
scala> res0("foo")
hello
scala> Test { x: String => println(s"hello $x") }
res2: String => Unit = <function1>
scala> res2("foo")
hello foo
scala> Test { x: String => throw new RuntimeException("ex") }
res4: String => Nothing = <function1>
scala> util.Try(res4("foo"))
res5: scala.util.Try[Nothing] = Failure(java.lang.RuntimeException: ex)
scala> Test { throw new RuntimeException("ex") }
res6: String => Nothing = <function1>
scala> util.Try(res6("foo"))
res7: scala.util.Try[Nothing] = Failure(java.lang.RuntimeException: ex)
You might be able to simplify a bit, add variance, etc.
Use:
val res3 = Test { (throw new RuntimeException("ex")): Any }
This works as expected. (No exception on creation, exception when calling res3).
A solution which uses reflection. (Still curious: can one write a static solution?)
import reflect.runtime.universe._
object Test {
def apply[A: TypeTag](thunk: => A): String => Any =
if (typeOf[A] =:= typeOf[Nothing]) // hah, caught you
_ => thunk
else if (typeOf[A] <:< typeOf[String => Any])
thunk.asInstanceOf[String => Any]
else
_ => thunk
}
val res0 = Test { println("hello") }
res0("foo") // --> hello
val res1 = Test { x: String => println(s"hello $x") }
res1("foo") // --> hello foo
val res2 = Test { x: String => throw new RuntimeException("ex") }
util.Try(res2("foo")) // --> Failure
val res3 = Test { throw new RuntimeException("ex") }
util.Try(res3("foo")) // --> Failure
(a macro based version of this would be static, I guess)