I am trying to cast a String to Int using extractors. My code looks as follows.
object Apply {
def unapply(s: String): Option[Int] = try {
Some(s.toInt)
} catch {
case _: java.lang.Exception => None
}
}
object App {
def toT[T](s: AnyRef): Option[T] = s match {
case v: T => Some(v)
case _ => None
}
def foo(param: String): Int = {
//reads a Map[String,String] m at runtime
toT[Int](m("offset")).getOrElse(0)
}
}
I get a runtime error: java.lang.String cannot be cast to java.lang.Integer. It seems the extractor is not being used at all. What should I do?
Edit: My use case is as follows. I am using play and I want to parse the query string passed in the url. I want to take the query string value (String) and use it as an Int, Double etc. For example,
val offset = getQueryStringAs[Int]("offset").getOrElse(0)
I think the biggest problem here is, that you seem to confuse casting and conversion. You have a Map[String, String] and therefore you can't cast the values to Int. You have to convert them. Luckily Scala adds the toInt method to strings through implicit conversion to StringOps.
This should work for you:
m("offset").toInt
Note that toInt will throw a java.lang.NumberFormatException if the string can not be converted to an integer.
edit:
What you want will afaik only work with typeclasses.
Here is an example:
trait StringConverter[A] {
def convert(x: String): A
}
implicit object StringToInt extends StringConverter[Int] {
def convert(x: String): Int = x.toInt
}
implicit object StringToDouble extends StringConverter[Double] {
def convert(x: String): Double = x.toDouble
}
implicit def string2StringConversion(x: String) = new {
def toT[A](implicit ev: StringConverter[A]) = ev.convert(x)
}
usage:
scala> "0.".toT[Double]
res6: Double = 0.0
There's a problem in your code, for which you should have received compiler warnings:
def toT[T](s: AnyRef): Option[T] = s match {
case v: T => Some(v) // this doesn't work, because T is erased
case _ => None
}
Now... where should Apply have been used? I see it declared, but I don't see it used anywhere.
EDIT
About the warning, look at the discussions around type erasure on Stack Overflow. For example, this answer I wrote on how to get around it -- though it's now deprecated with Scala 2.10.0.
To solve your problem I'd use type classes. For example:
abstract class Converter[T] {
def convert(s: String): T
}
object Converter {
def toConverter[T](converter: String => T): Converter[T] = new Converter[T] {
override def convert(s: String): T = converter(s)
}
implicit val intConverter = toConverter(_.toInt)
implicit val doubleConverter = toConverter(_.toDouble)
}
Then you can rewrite your method like this:
val map = Map("offset" -> "10", "price" -> "9.99")
def getQueryStringAs[T : Converter](key: String): Option[T] = {
val converter = implicitly[Converter[T]]
try {
Some(converter convert map(key))
} catch {
case ex: Exception => None
}
}
In use:
scala> getQueryStringAs[Int]("offset")
res1: Option[Int] = Some(10)
scala> getQueryStringAs[Double]("price")
res2: Option[Double] = Some(9.99)
Related
If we define the following function:
def methodWithImplicit(explicit: String)(implicit imp: String) = {
println(explicit + imp)
}
we can call it as follows:
methodWithImplicit("abc")("efg") //abc - explicit, efg - imp
And it works fine. Now consider the following TypeClass:
trait MyTypeClass[T] {
def accept(t: T): T
}
which is going to be used inside extractor object:
object TestExtractor {
def unapply(str: String)(implicit myTypeClass: MyTypeClass[String]): Option[String] =
if (!str.isEmpty)
Some(myTypeClass.accept(str))
else
None
}
So if we use it as follows:
implicit val myTypeClass:MyTypeClass[String] = new MyTypeClass[String] {
override def accept(t: String): Unit = t
}
"123" match {
case TestExtractor(str) => println(str)
}
It works ok. But how to pass the parameter explicitly when using with pattern matching? I tried
"123" match {
case TestExtractor(str)(myTypeClass) => println(str) //compile error
}
and
"123" match {
case TestExtractor(myTypeClass)(str) => println(str) //compile error
}
But it does not compile.
Since the left hand side seems to accept essentially nothing but trees built from stable identifiers, constant literals, and lower-case letters for variable names, I don't see any way to get closer to the desired syntax than this:
val `TestExtractor(myTypeClass)` = TestExtractor(myTypeClass)
"hello" match {
case `TestExtractor(myTypeClass)`(str) => println(str)
}
This of course requires that you define the weirdly named value TestExtractor(myTypeClass) (in backticks) right before the match-case, so you can use it as a single symbol.
Full code:
trait MyTypeClass[T] {
def accept(t: T): T
}
object TestExtractor { outer =>
def unapply(str: String)(implicit myTypeClass: MyTypeClass[String]): Option[String] =
if (!str.isEmpty)
Some(myTypeClass.accept(str))
else
None
class ExplicitTestExtractor(tc: MyTypeClass[String]) {
def unapply(t: String) = outer.unapply(t)(tc)
}
def apply(tc: MyTypeClass[String]): ExplicitTestExtractor =
new ExplicitTestExtractor(tc)
}
implicit val myTypeClass:MyTypeClass[String] = new MyTypeClass[String] {
override def accept(t: String): String = t.toUpperCase
}
val `TestExtractor(myTypeClass)` = TestExtractor(myTypeClass)
"hello" match {
case `TestExtractor(myTypeClass)`(str) => println(str)
}
It's been while Since I've started working on scala and I am wondering what kind of variable type is the best when I create a method which requires to return multiple data.
let's say If I have to make a method to get user info and it'll be called from many places.
def getUserParam(userId: String):Map[String,Any] = {
//do something
Map(
"isExist" -> true,
"userDataA" -> "String",
"userDataB" -> 1 // int
)
}
in this case, the result type is Map[String,Any] and since each param would be recognized as Any, You cannot pass the value to some other method requiring something spesifically.
def doSomething(foo: String){}
val foo = getUserParam("bar")
doSomething(foo("userDataA")) // type mismatch error
If I use Tuple, I can avoid that error, but I don't think it is easy to guess what each indexed number contains.
and of course there is a choice to use Case Class but once I use case class as a return type, I need to import the case class where ever I call the method.
What I want to ask is what is the best way to make a method returning more than 2 different variable type values.
Here are three options. Even though you might like the third option (using anonymous class) it's actually my least favorite. As you can see, it requires you to enable reflective calls (otherwise it throws a compilation warning). Scala will use reflection to achieve this which is not that great.
Personally, if there are only 2 values I use tuple. If there are more than two I will use a case class since it greatly improves code readability. The anonymous class option I knew it existed for a while, but I never used that it my code.
import java.util.Date
def returnTwoUsingTuple: (Date, String) = {
val date = new Date()
val str = "Hello world"
(date,str)
}
val tupleVer = returnTwoUsingTuple
println(tupleVer._1)
println(tupleVer._2)
case class Reply(date: Date, str: String)
def returnTwoUsingCaseClass: Reply = {
val date = new Date()
val str = "Hello world"
Reply(date,str)
}
val caseClassVer = returnTwoUsingCaseClass
println(caseClassVer.date)
println(caseClassVer.str)
import scala.language.reflectiveCalls
def returnTwoUsingAnonymousClass = {
val date = new Date()
val str = "Hello world"
new {
val getDate = date
val getStr = str
}
}
val anonClassVer = returnTwoUsingAnonymousClass
println(anonClassVer.getDate)
println(anonClassVer.getStr)
Sinse your logic with Map[String,Any] is more like for each key I have one of .. not for each key I have both ... more effective use in this case would be Either or even more effectively - scalaz.\/
scalaz.\/
import scalaz._
import scalaz.syntax.either._
def getUserParam(userId: String): Map[String, String \/ Int \/ Boolean] = {
//do something
Map(
"isExist" -> true.right,
"userDataA" -> "String".left.left,
"userDataB" -> 1.right.left
)
}
String \/ Int \/ Boolean is left-associatited to (String \/ Int) \/ Boolean
now you have
def doSomething(foo: String){}
unluckily it's the most complex case, if for example you had
def doSomethingB(foo: Boolean){}
you could've just
foo("userDataA").foreach(doSomethingB)
since the right value considered as correct so for String which is left to the left you could write
foo("userdata").swap.foreach(_.swap.foreach(doSomething))
Closed Family
Or you could craft you own simple type for large number of alternatives like
sealed trait Either3[+A, +B, +C] {
def ifFirst[T](action: A => T): Option[T] = None
def ifSecond[T](action: B => T): Option[T] = None
def ifThird[T](action: C => T): Option[T] = None
}
case class First[A](x: A) extends Either3[A, Nothing, Nothing] {
override def ifFirst[T](action: A => T): Option[T] = Some(action(x))
}
case class Second[A](x: A) extends Either3[Nothing, A, Nothing] {
override def ifSecond[T](action: A => T): Option[T] = Some(action(x))
}
case class Third[A](x: A) extends Either3[Nothing, Nothing, A] {
override def ifThird[T](action: A => T): Option[T] = Some(action(x))
}
now having
def getUserParam3(userId: String): Map[String, Either3[Boolean, String, Int]] = {
//do something
Map(
"isExist" -> First(true),
"userDataA" -> Second("String"),
"userDataB" -> Third(1)
)
}
val foo3 = getUserParam3("bar")
you can use your values as
foo3("userdata").ifSecond(doSomething)
Can't I use a generic on the unapply method of an extractor along with an implicit "converter" to support a pattern match specific to the parameterised type?
I'd like to do this (Note the use of [T] on the unapply line),
trait StringDecoder[A] {
def fromString(string: String): Option[A]
}
object ExampleExtractor {
def unapply[T](a: String)(implicit evidence: StringDecoder[T]): Option[T] = {
evidence.fromString(a)
}
}
object Example extends App {
implicit val stringDecoder = new StringDecoder[String] {
def fromString(string: String): Option[String] = Some(string)
}
implicit val intDecoder = new StringDecoder[Int] {
def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt)
}
val result = "hello" match {
case ExampleExtractor[String](x) => x // <- type hint barfs
}
println(result)
}
But I get the following compilation error
Error: (25, 10) not found: type ExampleExtractor
case ExampleExtractor[String] (x) => x
^
It works fine if I have only one implicit val in scope and drop the type hint (see below), but that defeats the object.
object Example extends App {
implicit val intDecoder = new StringDecoder[Int] {
def fromString(string: String): Option[Int] = Some(string.charAt(0).toInt)
}
val result = "hello" match {
case ExampleExtractor(x) => x
}
println(result)
}
A variant of your typed string decoder looks promising:
trait StringDecoder[A] {
def fromString(s: String): Option[A]
}
class ExampleExtractor[T](ev: StringDecoder[T]) {
def unapply(s: String) = ev.fromString(s)
}
object ExampleExtractor {
def apply[A](implicit ev: StringDecoder[A]) = new ExampleExtractor(ev)
}
then
implicit val intDecoder = new StringDecoder[Int] {
def fromString(s: String) = scala.util.Try {
Integer.parseInt(s)
}.toOption
}
val asInt = ExampleExtractor[Int]
val asInt(Nb) = "1111"
seems to produce what you're asking for. One problem remains: it seems that trying to
val ExampleExtractor[Int](nB) = "1111"
results in a compiler crash (at least inside my 2.10.3 SBT Scala console).
Long story short, I'm trying to figure out how to define a function from a generic input to a single-typed output.
The background: This is a continuation of Mapping over Shapeless record. After Travis's excellent answer, I now have the following:
import shapeless._
import poly._
import syntax.singleton._
import record._
type QueryParams = Map[String, Seq[String]]
trait RequestParam[T] {
def value: T
/** Convert value back to a query parameter representation */
def toQueryParams: Seq[(String, String)]
/** Mark this parameter for auto-propagation in new URLs */
def propagate: Boolean
protected def queryStringPresent(qs: String, allParams: QueryParams): Boolean = allParams.get(qs).nonEmpty
}
type RequestParamBuilder[T] = QueryParams => RequestParam[T]
def booleanRequestParam(paramName: String, willPropagate: Boolean): RequestParamBuilder[Boolean] = { params =>
new RequestParam[Boolean] {
def propagate: Boolean = willPropagate
def value: Boolean = queryStringPresent(paramName, params)
def toQueryParams: Seq[(String, String)] = Seq(paramName -> "true").filter(_ => value)
}
}
def stringRequestParam(paramName: String, willPropagate: Boolean): RequestParamBuilder[Option[String]] = { params =>
new RequestParam[Option[String]] {
def propagate: Boolean = willPropagate
def value: Option[String] = params.get(paramName).flatMap(_.headOption)
def toQueryParams: Seq[(String, String)] = value.map(paramName -> _).toSeq
}
}
In reality, the following would be a class constructor that takes this Map read from the query string as a parameter, but for simplicity's sake, I'm just defining a val:
val requestParams = Map("no_ads" -> Seq("true"), "edition" -> Seq("us"))
// In reality, there are many more possible parameters, but this is simplified
val options = ('adsDebug ->> booleanRequestParam("ads_debug", true)) ::
('hideAds ->> booleanRequestParam("no_ads", true)) ::
('edition ->> stringRequestParam("edition", false)) ::
HNil
object bind extends FieldPoly {
implicit def rpb[T, K](implicit witness: Witness.Aux[K]): Case.Aux[
FieldType[K, RequestParamBuilder[T]],
FieldType[K, RequestParam[T]]
] = atField(witness)(_(requestParams))
}
// Create queryable option values record by binding the request parameters
val boundOptions = options.map(bind)
This lets me do:
boundOptions.get('hideAds).value // -> true
The problem: Now I want to be able to reserialize options that have propagate = true. So basically, I need to filter my HList on the propagate field of every member, which should always return a Boolean, and then have each parameter reserialize itself to a Seq[(String, String)]. I've tried the following:
object propagateFilter extends (RequestParam ~> Const[Boolean]) {
override def apply[T](r: RequestParam[T]): Boolean = r.propagate
}
object unbind extends (RequestParam ~> Const[Seq[(String, String)]]) {
override def apply[T](r: RequestParam[T]): Seq[(String, String)] = r.toQueryParams
}
// Reserialize a query string for options that should be propagated
val propagatedParams = boundOptions.values.filter(propagateFilter).map(unbind).toList
// (followed by conventional collections methods)
, but it doesn't like my functions. I got the following error:
<console>:31: error: type mismatch;
found : Boolean
required: shapeless.Const[T]
(which expands to) AnyRef{type λ[T] = T}
override def apply[T](r: RequestParam[T]) = r.propagate
I believe I'm taking the wrong approach to a function that's supposed to have a polymorphic input but monomorphic output.
Other failed attempts:
object propagateFilter extends Poly1 {
implicit def default[T](implicit st: Case.Aux[RequestParam[T], Boolean]) = at[RequestParam[T]](_.propagate)
}
and
def propagate[T](x: RequestParam[T]): Boolean = x.propagate
and
object propagateFilter extends Poly1 {
implicit def default = at[RequestParam[_]](_.propagate)
}
and
object propagateFilter extends FieldPoly {
implicit def rpb[T, K](implicit witness: Witness.Aux[K]): Case.Aux[
FieldType[K, RequestParam[T]],
Boolean
] = atField(witness)(_.propagate)
}
None of which work, probably due to my own misunderstanding of what's going on.
I am trying to write some extension methods for the Scala collections, and running into trouble fully generifying them.
A first attempt at tailOption yields something like:
implicit class TailOption[A, Repr <: GenTraversableLike[A, Repr]](val repr: Repr) {
def tailOption: Option[Repr] =
if (repr.isEmpty) None
else Some(repr.tail)
}
unfortunately, this doesn't work:
scala> List(1,2,3).tailOption
<console>:19: error: value tailOption is not a member of List[Int]
List(1,2,3).tailOption
Scala 2.10 provides the IsTraversableLike type-class to help adapt this sort of thing for all collections (including odd ones, like Strings).
With this I can for instance implement tailOption quite easily:
implicit class TailOption[Repr](val r: Repr)(implicit fr: IsTraversableLike[Repr]) {
def tailOption: Option[Repr] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.tail)
}
}
scala> List(1,2,3).tailOption
res12: Option[List[Int]] = Some(List(2, 3))
scala> "one".tailOption
res13: Option[String] = Some(ne)
The result is of the correct type: Option[<input-type>]. Specifically, I have been able to preserve the Repr type when calling methods that return Repr, like `tail.
Unfortunately, I can't seem to use this trick to preserve the type of the elements of the collection. I can't call methods that return an element.
IsTraversableLike does have a member A but it doesn't seem very useful. In particular I can't reconstruct my original element type and the member is not equivalent in type. For instance, without further work, headTailOption looks like this:
implicit class HeadTailOption[Repr](val r: Repr)(implicit val fr: IsTraversableLike[Repr]) {
def headTailOption: Option[(fr.A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
scala> val Some((c, _)) = "one".headTailOption
c: _1.fr.A forSome { val _1: HeadTailOption[String] } = o
As we can see, c has a wonderfully baroque type. But, this type is not equivalent to Char:
scala> val fr = implicitly[IsTraversableLike[String]]
fr: scala.collection.generic.IsTraversableLike[String] = scala.collection.generic.IsTraversableLike$$anon$1#60ab6a84
scala> implicitly[fr.A <:< Char]
<console>:25: error: Cannot prove that fr.A <:< Char.
implicitly[fr.A <:< Char]
I have tried all sorts of tricks including having Repr[A] <: GenTraversableLike[A, Repr[A]] none of which help. Can anyone work out the magic sauce to make headTailOption return the right types for:
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption
A partial answer. You have probably started from the scaladoc example for IsTraversableLike. It still uses the "old approach" of separating implicit conversion and instantiating the wrapper class, instead of going in one step through an implicit class. It turns out that the "old approach" does work:
import collection.GenTraversableLike
import collection.generic.IsTraversableLike
final class HeadTailOptionImpl[A, Repr](repr: GenTraversableLike[A, Repr]) {
def headTailOption: Option[(A, Repr)] = {
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
implicit def headTailOption[Repr](r: Repr)(implicit fr: IsTraversableLike[Repr]):
HeadTailOptionImpl[fr.A,Repr] = new HeadTailOptionImpl(fr.conversion(r))
// `c` looks still weird: `scala.collection.generic.IsTraversableLike.stringRepr.A`
val Some((c, _)) = "one".headTailOption
val d: Char = c // ...but it really is a `Char`!
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption
As Miles points out, the split seems essential for this to work with the implicit search and type inference.
Another solution, although of course less elegant, is to give up the unification of strings and collections:
trait HeadTailOptionLike[A, Repr] {
def headTailOption: Option[(A, Repr)]
}
implicit class GenHeadTailOption[A, Repr](repr: GenTraversableLike[A, Repr])
extends HeadTailOptionLike[A, Repr] {
def headTailOption =
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
implicit class StringHeadTailOption(repr: String)
extends HeadTailOptionLike[Char, String] {
def headTailOption =
if (repr.isEmpty) None
else Some(repr.head -> repr.tail) // could use repr.charAt(0) -> repr.substring(1)
}
List(1,2,3).headTailOption
"one".headTailOption
You can write it as an implicit class if you extract the type A from the IsTraversableLike.
import collection.generic.IsTraversableLike
implicit class HeadTailOption[Repr,A0](val r: Repr)(implicit val fr: IsTraversableLike[Repr]{ type A = A0 }) {
def headTailOption: Option[(A0, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
Or equivalently:
import collection.generic.IsTraversableLike
type IsTraversableLikeAux[Repr,A0] = IsTraversableLike[Repr]{ type A = A0 }
implicit class HeadTailOption[Repr,A](val r: Repr)(implicit val fr: IsTraversableLikeAux[Repr,A]) {
def headTailOption: Option[(A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
And then everything works fine.
scala> val Some((c, _)) = "one".headTailOption
c: scala.collection.generic.IsTraversableLike.stringRepr.A = o
scala> c.isSpaceChar
res0: Boolean = false
The compiler knows that scala.collection.generic.IsTraversableLike.stringRepr.A is the same as Char.