Please take a look at the following example:
trait MyTrait {
def myTraitMeth : String
}
object TraitImplementation extends MyTrait {
def myTraitMeth = "Works fine"
def myExtraMeth = "Doesn't work"
}
case object Manager {
def returnImplementation : MyTrait = TraitImplementation
}
println(Manager.returnImplementation.myExtraMeth)
In this scenario, what is happening is that I can't access the extra method of the trait implementation, TraitImplementation, because I defined the return method of the method returnImplementation to be of the type MyTrait - I cannot change this condition.
An obvious solution would be enforcing this extra method on the trait, but that is not an option for me, given the fact that other implementations of the MyTrait cannot have such a method.
What I really need is to make sure that the method returnImplementation will return something that is an implementation of MyTrait, and, at the same time, allow the caller of that method to use all methods that have been implemented, not only those enforced on the trait.
I tried messing around with types, going with something like
case object Manager {
def returnImplementation [A <: MyTrait] : A = TraitImplementation
}
but this leads to a type mismatch, because the compiler cannot understand that A is a generic type.
Any ideas on how to accomplish it?
I originally wanted to leave this as a comment, but there was a discussion going on so that the space was getting kind of crowded. I decided to write it up as an answer instead.
This problem you have sounds like something you would get around by using case matching. When returnImplementation returns a trait of type MyTrait, case match on it to get the desired subclass, and depending on which subclass it is, have different behavior. Wrap it in an Option if you want monadic fail-fast behavior, so that only certain subclass will trigger the creation of some result. The result will be Some(...) if the desired subclass with the desired method was found, None otherwise.
trait MyTrait {
def myTraitMeth : String
}
object TraitImplementation extends MyTrait {
def myTraitMeth = "Works fine"
def myExtraMeth = "Doesn't work"
}
case object Manager {
def returnImplementation : MyTrait = TraitImplementation
}
For your println statement, you would call it like so:
Manager.returnImplementation match {
case TraitImplementation => println(TraitImplementation.myExtraMeth)
case _ =>
}
If you want to keep your code purely functional with no side-effects like println functions, do the following:
val result = Manager.returnImplementation match {
case TraitImplementation => Some(TraitImplementation)
case _ => None
}
result will be of type Option[TraitImplementation] and you can pass it around for context dependent behavior.
If you have side effecting code, like your println statement, you can isolate it from the rest of your purely function code by calling foreach on this Option like so:
result.foreach(x => println(x.myExtraMeth))
Based on the discussion Luis and you had, you can also case match on MyExtTrait for the desired behavior.
trait MyExtTrait {
def myExtraMeth: String
}
val result = Manager.returnImplementation match {
case x: MyExtTrait => println(x.myExtraMeth)
case _ =>
}
or
val result = Manager.returnImplementation match {
case x: MyExtTrait => Some(x)
case _ => None
}
result.foreach(x => println(x.myExtraMeth))
Related
A bit of a funky scenario, best outlined below.
Suppose I have sealed trait Painting[T], and then a bunch of more specialised variations, such as trait ImpressionistPainting[T] extends Painting[T] and so on, building a simple sealed type family.
I then have a class with a f bounded polymorphic type bound as such:
class Gallery[T <: Gallery[T]]()(implicit helper: GalleryHelper[T])
And a:
trait GalleryHelper[T <: Gallery[T]] {
def paintings: Set[Painting[_]]
}
object GalleryHelper {
implicit def materialize[T <: Gallery[T]]: GalleyHelper[T] = {
macro MyMacro.materialize[T]
}
def apply[T <: Gallery[T]]()(
implicit ev: GalleryHelper[T]
): GalleryHelper[T] = ev
}
So far this is very basic and straightforward foo bar code.
The whole goal of this setup is to macro materialise a helper list of items that I need to describe the gallery, or in this case arbitrarily typed "user content", as such:
class MyGallery extends Gallery[MyGallery] {
object `le-reve` extends CubistPainting[Picasso]
object starry_night extends PostImpressionistPainting[VanGogh]
// ..
}
Now with some macro compat fun, I want to macro materialise the helper in question and filter the members of T <: Gallery[T] to extract those which are MemberType <:< Painting[_].
All very straightforward, the below is more complex than simply type.decls.filter(_.typeSignature <:< typeOf[Filter] because it needs to return a list of all inherited members in the order they are written as well, given galleries extend other galleries for instance.
def findMembersWithBound[T : WeakTypeTag, Filter : TypeTag](
exclusions: Symbol => Option[Symbol] = { s: Symbol => Some(s) }
): Set[Symbol] = {
val tpe = weakTypeOf[T].typeSymbol.typeSignature
(
for {
baseClass <- tpe.baseClasses.reverse.flatMap(exclusions(_))
symbol <- baseClass.typeSignature.members.sorted
if symbol.typeSignature <:< typeOf[Filter]
} yield symbol
)(collection.breakOut)
}
So in an implicit macro, a basic traversal of module members for type T would need to filter by a sub type, in this case Painting[_], and then look at what specific type arguments where provided by the user when extending a variant of Painting. The type family is sealed, so users extend a sub class of Painting with object, never Painting[_] directly, if this is relevant in any way.
#macrocompat.bundle
class MyMacro(val c: blackbox.Context) {
import c.universe._
def materialize[T <: Gallery[T]]: Tree = {
val galleryTpe = weakTypeOf[T]
val fields = findMembersWithBound[T, Painting[_]](exclusions)
val colMembers = sourceMembers.map { member =>
val memberType = member.typeSignatureIn(galleryTpe)
memberType.baseClasses.find(colSymbol ==) match {
case Some(root) => {
// Herein lies the problem, typeArgs is Nil.
root.typeSignatureIn(memberType).typeArgs.headOption match {
case Some(colSignature) => colSignature
case None => c.abort(
c.enclosingPosition,
s"Could not find the artist for ${member.asModule.name}"
)
}
}
case None => c.abort(c.enclosingPosition, s"Could not find root painting type for ${member.asModule.name}")
}
}
}
The problem is that none of the original type arguments passed through to Painting are visible anymore, even though the typeSignature would apper to be evaluated in scope and so on, and I'm simply trying to make sure Van Gogh doesn't become the proverbial Waldo.
What is the correct API to dealias or however else make those typeArgs visible again? Currently an empty list.
Ok turns out there's a "well hidden" way to do this using asSeenFrom. The relevant part is:
root.typeSignature.typeParams match {
case head :: Nil => head.asType.toType.asSeenFrom(memberType, colSymbol)
case _ => c.abort(
c.enclosingPosition,
"Expected exactly one type parameter provided for painting type"
)
}
I am using the scala Enumeration type in combination with Play Framework's Reads and Writes. I would like to have a trait like:
trait EnumerationWrites[T <: Enumeration] {
def reads(jsonValue: JsValue): JsResult[T] = jsonScope match {
case JsString(s) => JsSuccess(T.withName(s)) <-- ERROR!
case _ => JsError("String value expected")
}
}
and then I would do something like
object MyObject extends EnumerationTrait[T]
This doesn't work - the compiler is not able to resolve the T type within the case matching. What is the problem?
Bad news: you can not call method withName of type parameter. You need an object.
Good news: this object could be implicit. Which you already know if you are familiar with realization of typeclass concept in scala.
So for general use deserializer for Enumeration you could use function like this:
implicit def enumerationReads[T <: Enumeration](implicit enum: T): Reads[enum.Value] = {
val names: Set[String] = enum.values map (_.toString)
Reads {
case JsString(s) => if (names contains s) JsSuccess(enum withName s)
else JsError(s"could not find value '$s' for $enum")
case _ => JsError("String value expected")
}
}
As you can see it demands enumeration to be implicitly available, so you should declare enumeration for this like
implicit case object Colors extends Enumeration {
val Red, Blue = Value
}
Or provide some implicit value for your existing objects like
implicit val colorsEvidence = Colors
I've got a typeclass pattern in scala and I'd like a method that can be called against any type and return an option based on whether there is an appropriate typeclass available in scope. Concretely, I have:
trait Truthy[A] {
def toBoolean(a:A):Boolean
def unapply(a:Any):Option[Boolean]
}
object Truthy {
implicit object IntTruthy extends Truthy[Int] {
def toBoolean(i:Int) = i == 1
def unapply(a:Any) = a match {
case i:Int => Some(toBoolean(i))
case _ => None
}
}
implicit object BoolTruthy extends Truthy[Boolean] {
def toBoolean(b:Boolean) = b
def unapply(a:Any) = a match {
case i:Boolean => Some(toBoolean(i))
case _ => None
}
}
implicit object StringTruthy extends Truthy[String] {
def toBoolean(s:String) = Set("t", "true", "yes", "y").contains(s.toLowerCase)
def unapply(a:Any) = a match {
case i:String => Some(toBoolean(i))
case _ => None
}
}
def truthy[A](a:A)(implicit ev:Truthy[A]) = ev.toBoolean(a)
}
The truthy method is fine when I know the type of my argument, but I'm consuming data from a source that lacks that type info, so I'd like a function with signature Any => Option[Boolean] that will try all of the Truthy implementations in scope and return the result if one can be found. Obviously I could write
def getTruth(a:Any) = a match {
case IntTruthy(b) => Some(b)
case BoolTruthy(b) => Some(b)
case StringTruthy(b) => Some(b)
case _ => None
}
but that would defeat the whole purpose of the 'openness' of typeclasses.
The ability of the compiler to determine a valid implicit Truthy is limited by the available information at compile time. That means, from the moment you're working with an Any, which says nothing at all of the type, you'll have to "manually" identify the A type, so the compiler can find the Truthy you need.
Then your getTruth would look like:
def getTruth(any: Any): Option[Boolean] = any match {
case i : Int => Some(truthy(i))
case b : Boolean => Some(truthy(b))
...
case _ => None
}
Chirlo's answer is correct. I would add for clarification that the logic to "try all of the Truthy implementations in scope" does not exist. In principle, the compiler should not instantiate every possible object just because it is in scope, unless it is actually referenced or required in some way. Hence, what is "in scope" at compile time due to adding an import would not be there in runtime at all. This can be easily tested:
object Foo {
println("initializing foo")
def sayHello() = println("hello!")
}
object Test2 {
def main(args: Array[String]): Unit = {
val me = "Daniel"
println(s"Hey, I'm $me")
Foo.sayHello()
}
}
Prints:
Hey, I'm Daniel
initializing foo
hello!
If you comment Foo.sayHello() you will see how initializing foo goes away too. The object will not be there in runtime.
In your case, adding a type explicitly allows the compiler to statically define what implicit will be instantiated and referenced (if any).
These java specs might help clarify too.
I keep coming across situations where I want to use extractors as parsers, they are really useful for this but it never looks right, often the unapply looks like it should be an apply. Also, the parsing extractor may get in the way of the default extractor. Are there any patterns for this?
case class AnID(int: Int) extends AnyVal
object AnID {
def unapply(idString: String): Option[AnID] = "id-([0-9]+)".r match {
case Seq(intString: String) => Try(Integer.parseInt(intString)).map(AnID.apply).toOption
case _ => None
}
}
And a test:
AnID(8) should be (AnID(8))
val AnID(id1) = "id-1"
id1 should be (AnID(1))
val AnID(id2) = AnID(2)
id2 should be (2)
It is kind of strange.
You can create a Parse object inside the companion object to make it more clear that you're parsing.
case class AnID(int: Int) extends AnyVal
object AnID {
private val Reg = "id-([0-9]+)".r
object Parse {
def unapply(s: String): Option[AnID] = s match {
case Reg(digits) => Some(new AnID(digits.toInt))
case _ => None
}
}
}
So now you at least don't clobber your normal extractor and have things that look like val AnID.Parse(id) = "id-9".
Maybe that won't solve your general unease with pattern matching looking kind of backwards. If not, you can always make Parse just implement an apply, and then you get val Option(x) = AnID.Parse("id-9").
I'm writing a generic value parser using Scala 2.10.
The input is a string and the output is a generic type, given by the user.
The only thing I can come up with is
val StringTYPE = classOf[java.lang.String]
def parseValue[T: ClassTag](str: String): T = {
implicitly[ClassTag[T]].runtimeClass match {
case java.lang.Integer.TYPE => str.toInt.asInstanceOf[T]
case java.lang.Long.TYPE => str.toLong.asInstanceOf[T]
case StringTYPE => str.asInstanceOf[T]
case _ => throw new Exception("Unknown type")
}
}
But it seems very verbose and complicated, so I'm wondering is there any simpler way to do this?
It seems strange to use a run-time error for a compile-time condition. Did you consider a type class?
trait Readable[T] {
def read(str: String): T
}
object Readable {
implicit object IntIsReadable extends Readable[Int] {
def read(str: String): Int = str.toInt
}
// ... provide similar objects for any types that can be "read" ...
// if possible, inside object Readable
// or inside the companion object of the type you want to make readable.
// Otherwise, ensure that the implicit is in scope when calling Read
}
def readValue[T: Readable](str: String): T = implicitly[Readable[T]].read(str)
The solution is given by Aaron, the proper way to do that is the type class.
Just to suggest minor improvements to your version (but do not do that) you could check directly with the ClassTag. Also, naming the implicit parameter might be easier than getting it back with implicitly:
def parseValue[T](str: String)(implicit tag: ClassTag[T]): T = {
if(tag == ClassTag.Int) str.toInt.asInstanceOf[T]
else if(tag == ClassTag.Long) ...
else if (tag == ClassTag(classOf[String]) …
else ???
}