What happens in line nine below that makes the result variable accessible on line ten?
The example is from the Akka documentation on testing. The Ask in line eight returns a scala.concurrent.Future. The Future.value() returns an Option[Try[T]], which will either be Some(Success(t)) or Some(Failure(error)). Then Some.get is called, which should either return the t or the error, depending the result of the Try.
It seems like whether or not the value of future.value.get is an error in line nine, it is attempting to instantiate a new Success, which is defined as a case class in Try, with the return value from Some.get. The Success on line nine is not used directly, but instead the case class constructor parameter result somehow makes it into scope so it can be used in line ten. What is this called in Scala? Where can I find out more about how this syntax works?
1. import akka.testkit.TestActorRef
2. import scala.concurrent.duration._
3. import scala.concurrent.Await
4. import akka.pattern.ask
5.
6. val actorRef = TestActorRef(newMyActor)
7. // hypothetical message stimulating a '42' answer
8. val future = actorRef ? Say42
9. val Success( result: Int ) = future.value.get
10. result should be (42)
val Success( result: Int ) = future.value.get is a pattern match. You can use pattern-matching to assign values to identifiers when declaring a val. It's about the same as writing:
val result: Int = future.value.get match {
case Success(r: Int) => r
}
Notice how this is not an exhaustive match, though, and if future.value.get is a Failure, then a MatchError will be thrown. In the context of unit tests, I use pattern matching like this all the time, since a MatchError would be another indication of failure.
Here are a few examples of similar (safer) pattern-matching assignments:
val (a, b) = (1, 2)
case class Test(i: Int, j: String)
val test = Test(1, "a")
val (i, j) = test
val list = List(1, 2, 3, 4)
val List(first, second, _*) = list // though this will fail if the List has less than 3 elements
That's just pattern matching. For instance:
scala> val Some(a) = Some(5)
a: Int = 5
scala> val Some(a) = None: Option[Int]
scala.MatchError: None (of class scala.None$)
... 33 elided
is equivalent to:
scala> val a = Some(5) match {case Some(a) => a}
a: Int = 5
scala> val a = (None: Option[Int]) match {case Some(a) => a}
scala.MatchError: None (of class scala.None$)
... 33 elided
in both cases Some.unapply method (which is part of companion-object, generated automatically for case class) is called.
In general, for an expression like val Extractor(a, Extractor(b, c)) = input scala-compiler internally generates (you may check it with macros) special synthetic expressions:
val tuple = input match { //synthetic value here
Extractor(a, Extractor(b, c)) => (a,b,c)
}
val a = tuple._1
val b = tuple._2
val c = tuple._3
This is called Pattern Matching.
Related
I mistakenly concatted a string with an Option[String] while coding in scala.
I expected as a strongly typed language, scala would not allow me to do such operation.
This is what I tried.
This works
scala> val a:String = "aaa"
val a: String = aaa
scala> val b:Option[String] = Some("bbbb")
val b: Option[String] = Some(bbbb)
scala> a + b
val res0: String = aaaSome(bbbb)
scala> val c:Option[String] = None
val c: Option[String] = None
scala> val d = a + c
val d: String = aaaNone
scala> val e = 1
val e: Int = 1
scala> a + e
val res2: String = aaa1
while this does not work
scala> val f:Option[String] = Some("ffff")
val f: Option[String] = Some(ffff)
scala> val g:Option[String] = None
val g: Option[String] = None
scala> f + g
^
error: type mismatch;
found : Option[String]
required: String
Why does scala allow such behavior? Dynamically typed languages like python will stop me from adding strings to int types, None types or any type other than strings. Curious if this design is intentional? If so why?
Scala contains an implicit class any2stringadd in it's Predef package. This class is responsible for these concatenation operations.
implicit final class any2stringadd[A](private val self: A) extends AnyVal {
def +(other: String): String = String.valueOf(self) + other
}
What it means is that, by default, scope contains a method + which can concatenate value of any type A with string by converting value of this type to string via String.valueOf(...).
I can't speak of design choices, I agree that this might be an unexpected behavior. The same applies to Scala's native == method. For example, this code compiles just ok: Some("a") == "b". This can lead to nasty bugs in filtering and other methods.
If you want to eliminate this behavior I suggest you take a look at https://typelevel.org/cats/ library, which introduces different typeclasses that can solve this problem.
For example, for string concatenation you can use Semigroup typeclass (which has tons of other useful use-cases as well):
import cats.Semigroup
Semigroup[String].combine("a", "b") // works, returns "ab"
Semigroup[String].combine("a", Some("b")) // won't work, compilation error
This looks tedious, but there is a syntactic sugar:
import cats.implicits._
"a" |+| "b" // works, returns "ab"
"a" |+| Some("b") // won't work, compilation error
// |+| here is the same as Semigroup[String].combine
The same thing applies to == method. Instead you can use Eq typeclass:
import cats.implicits._
"a" == Some("b") // works, no error, but could be unexpected
"a" === Some("b") // compilation error (Cats Eq)
"a" === "b" // works, as expected
"a" =!= "b" // same as != but type safe
I'm trying to use a partial function for some validations, lets take an example of a string:
def isLengthValid: PartialFunction[String, Option[String]] ={
case s:String if s.length > 5 => Some("Invalid")
}
def isStringValid: PartialFunction[String, Option[String]] ={
case s: String if s == "valid" => Some("Valid")
}
isLengthValid("valid") orElse isStringValid("valid")
expected output => Some("Valid")
But I'm getting a match Error:
scala.MatchError: valid (of class java.lang.String)
Could anyone help that what is going wrong here, because as per my understanding .isDefinedAt is called internally and is should not give matchError.
P.S ignore the inputs, this is just an example.
Your understanding is wrong. The ScalaDocs page clearly states, "It is the responsibility of the caller to call isDefinedAt before calling apply ...".
Your code isn't calling isDefinedAt, which is causing the exception, so you have to explicitly call it or you can employ other methods that hide the isDefinedAt internally.
Seq("valid") collect (isLengthValid orElse isStringValid)
//res0: Seq[Option[String]] = List(Some(Valid))
Seq("vlad") collect (isLengthValid orElse isStringValid)
//res1: Seq[Option[String]] = List()
This works as intended if you write the last line as
(isLengthValid orElse isStringValid)("valid")
I suspect the problem is that your version desugars to
(isLengthValid.apply("valid")).orElse(isStringValid.apply("valid"))
This means the apply is calculated before the orElse takes place, which means the partial function is treated as a total function and a match error is thrown as Valy Dia's answer explains. The orElse is actually being called on the result output, not the partial function.
The error message comes from the first expression - isLengthValid.
It is define only for string with a length stricly greater than 5. Hence when it is applied to a the string "valid" of length 5, it throws a MatchError:
scala>"valid".length
res5: Int = 5
isLengthValid("valid")
scala.MatchError: valid (of class java.lang.String)
If the method isLengthValid defined this way instead (Note the greater than equal sign), it wouldn't throw the MatchError :
def isLengthValid: PartialFunction[String, Option[String]] ={
case s:String if s.length >= 5 => Some("Invalid")
}
scala>isLengthValid("valid")
res8: Option[String] = Some("Invalid")
And the original expression would return an Option:
scala>isLengthValid("valid") orElse isStringValid("valid")
res9: Option[String] = Some("Invalid")
What you could do here as well as explained in this question, is to use this definition instead:
val isLengthValid = new PartialFunction[String, Option[String]] {
def isDefinedAt(x: String) = x.length > 5
def apply(x: String) = Some("Invalid")
}
scala>isLengthValid("valid")
res13: Some[String] = Some("Invalid")
I'm fairly new to Scala and very new to writing macros and looking for a little help/advise. I have the following code...
trait ValidationRule
case class Required() extends ValidationRule
case class HasLength(l: Int) extends ValidationRule
case class Person(name: String)
myMacro[Person] { p => p.name.is(Required(), HasLength(255)) }
Obviously there is some missing code here but this is just pseudo to get the question out.
So given a Tree representing p => p.name.is(Required(), HasLength(255)) I'm trying to write a match/case to select out all expressions representing a ValidationRule. Something like:
case TypeApply(Select(_, ....
Can anyone suggest the best match case to be able to extract a List of Trees that represent each "all" ValidationRules from within the "is" method?
You should definitely look into Quasiquotes.
Quasiquotes are used to do two things: to build Trees, and to pattern match Trees. They allow you to express the tree that you want to work with in terms of the equivalent Scala code. You let the quasiquote library deal with how Scala code maps to a Tree graph, and that's a good thing!
You can play around with them in the REPL, though the results might be slightly different in the macro universe:
scala> import scala.reflect.runtime.universe._
scala> showRaw(cq"p => p.name.is(Required(), HasLength(255))")
res0: String = CaseDef(
Bind(
TermName("p"),
Ident(termNames.WILDCARD)),
EmptyTree,
Apply(
Select(
Select(
Ident(TermName("p")),
TermName("name")),
TermName("is")),
List(
Apply(
Ident(TermName("Required")),
List()),
Apply(
Ident(TermName("HasLength")),
List(Literal(Constant(255)))))))
The other thing you can do with Quasiquotes is to actually use them to pattern match.
scala> val fromTree = cq"p => p.name.is(Required(), HasLength(255))"
scala> val cq"p => p.name.is($x, $y)" = fromTree
x: reflect.runtime.universe.Tree = Required()
y: reflect.runtime.universe.Tree = HasLength(255)
Now, you have to be careful, because that pattern ONLY matches if the user named their pattern variable p.
scala> val fromTree = cq"x => x.name.is(Required(), HasLength(255))"
scala> val cq"p => p.name.is($x, $y)" = fromTree
scala.MatchError: case (x # _) => x.name.is(Required(), HasLength(255)) (of class scala.reflect.internal.Trees$CaseDef)
... 33 elided
Instead, you'll want to be a bit more generic:
scala> val cq"${p1:TermName} => ${p2:TermName}.name.is($x, $y)" = fromTree
p1: reflect.runtime.universe.TermName = x
p2: reflect.runtime.universe.TermName = x
x: reflect.runtime.universe.Tree = Required()
y: reflect.runtime.universe.Tree = HasLength(255)
scala> p1 == p2
res2: Boolean = true
And, of course, if you were doing this as part of a pattern match, you could do:
case cq"${p1:TermName} => ${p2:TermName}.name.is($x, $y)" if p1 == p2 =>
???
Keep in mind that Macros are a deep, dark hole. If you're just getting started, expect to spend a lot of time getting your macro code correct. After that, expect to spend a lot of time dealing with edge cases.
What happens in line nine below that makes the result variable accessible on line ten?
The example is from the Akka documentation on testing. The Ask in line eight returns a scala.concurrent.Future. The Future.value() returns an Option[Try[T]], which will either be Some(Success(t)) or Some(Failure(error)). Then Some.get is called, which should either return the t or the error, depending the result of the Try.
It seems like whether or not the value of future.value.get is an error in line nine, it is attempting to instantiate a new Success, which is defined as a case class in Try, with the return value from Some.get. The Success on line nine is not used directly, but instead the case class constructor parameter result somehow makes it into scope so it can be used in line ten. What is this called in Scala? Where can I find out more about how this syntax works?
1. import akka.testkit.TestActorRef
2. import scala.concurrent.duration._
3. import scala.concurrent.Await
4. import akka.pattern.ask
5.
6. val actorRef = TestActorRef(newMyActor)
7. // hypothetical message stimulating a '42' answer
8. val future = actorRef ? Say42
9. val Success( result: Int ) = future.value.get
10. result should be (42)
val Success( result: Int ) = future.value.get is a pattern match. You can use pattern-matching to assign values to identifiers when declaring a val. It's about the same as writing:
val result: Int = future.value.get match {
case Success(r: Int) => r
}
Notice how this is not an exhaustive match, though, and if future.value.get is a Failure, then a MatchError will be thrown. In the context of unit tests, I use pattern matching like this all the time, since a MatchError would be another indication of failure.
Here are a few examples of similar (safer) pattern-matching assignments:
val (a, b) = (1, 2)
case class Test(i: Int, j: String)
val test = Test(1, "a")
val (i, j) = test
val list = List(1, 2, 3, 4)
val List(first, second, _*) = list // though this will fail if the List has less than 3 elements
That's just pattern matching. For instance:
scala> val Some(a) = Some(5)
a: Int = 5
scala> val Some(a) = None: Option[Int]
scala.MatchError: None (of class scala.None$)
... 33 elided
is equivalent to:
scala> val a = Some(5) match {case Some(a) => a}
a: Int = 5
scala> val a = (None: Option[Int]) match {case Some(a) => a}
scala.MatchError: None (of class scala.None$)
... 33 elided
in both cases Some.unapply method (which is part of companion-object, generated automatically for case class) is called.
In general, for an expression like val Extractor(a, Extractor(b, c)) = input scala-compiler internally generates (you may check it with macros) special synthetic expressions:
val tuple = input match { //synthetic value here
Extractor(a, Extractor(b, c)) => (a,b,c)
}
val a = tuple._1
val b = tuple._2
val c = tuple._3
This is called Pattern Matching.
Edit
originally the question was "Collection to Tuple" as I assumed I needed a tuple in order to do variable multi-assignment. It turns out that one can do variable multi-assignment directly on collections. Retitled the question accordingly.
Original
Have a simple Seq[String] derived from a regex that I would like to convert to a Tuple.
What's the most direct way to do so?
I currently have:
val(clazz, date) = captures match {
case x: Seq[String] => (x(0), x(1))
}
Which is ok, but my routing layer has a bunch of regex matched routes that I'll be doing val(a,b,c) multi-assignment on (the capture group is always known since the route is not processed if regex does not match). Would be nice to have a leaner solution than match { case.. => ..}
What's the shortest 1-liner to convert collections to tuples in Scala?
This is not an answer to the question but might solve the problem in a different way.
You know you can match a xs: List[String] like so:
val a :: b :: c :: _ = xs
This assigns the first three elements of the list to a,b,c? You can match other things like Seq in the declaration of a val just like inside a case statement. Be sure you take care of matching errors:
Catching MatchError at val initialisation with pattern matching in Scala?
You can make it slightly nicer using |> operator from Scalaz.
scala> val captures = Vector("Hello", "World")
captures: scala.collection.immutable.Vector[java.lang.String] = Vector(Hello, World)
scala> val (a, b) = captures |> { x => (x(0), x(1)) }
a: java.lang.String = Hello
b: java.lang.String = World
If you don't want to use Scalaz, you can define |> yourself as shown below:
scala> class AW[A](a: A) {
| def |>[B](f: A => B): B = f(a)
| }
defined class AW
scala> implicit def aW[A](a: A): AW[A] = new AW(a)
aW: [A](a: A)AW[A]
EDIT:
Or, something like #ziggystar's suggestion:
scala> val Vector(a, b) = captures
a: java.lang.String = Hello
b: java.lang.String = World
You can make it more concise as shown below:
scala> val S = Seq
S: scala.collection.Seq.type = scala.collection.Seq$#157e63a
scala> val S(a, b) = captures
a: java.lang.String = Hello
b: java.lang.String = World
As proposed by #ziggystar in comments you can do something like:
val (clazz, date) = { val a::b::_ = capture; (a, b)}
or
val (clazz, date) = (capture(0), capture(1))
If you verified the type of the list before it is OK, but take care of the length of the Seq because the code will run even if the list is of size 0 or 1.
Your question is originally specifically about assigning the individual capturing groups in a regex, which already allow you to assign from them directly:
scala> val regex = """(\d*)-(\d*)-(\d*)""".r
regex: scala.util.matching.Regex = (\d*)-(\d*)-(\d*)
scala> val regex(a, b, c) = "29-1-2012"
d: String = 29
m: String = 1
y: String = 2012
obviously you can use these in a case as well:
scala> "29-1-2012" match { case regex(d, m, y) => (y, m, d) }
res16: (String, String, String) = (2012,1,29)
and then group these as required.
Seqs to tuple
To perform multi-assignment from a Seq, what about the following?
val Seq(clazz, date) = captures
As you see, no need to restrict to Lists; this code will throw a MatchError if the length does not match (in your case, that's good because it means that you made a mistake). You can then add
(clazz, date)
to recreate the tuple.
Tuples from matches
However, Jed Wesley-Smith posted a solution which avoids this problem and solves the original question better. In particular, in your solution you have a Seq whose length is not specified, so if you make a mistake the compiler won't tell you; with tuples instead the compiler can help you (even if it can't check against the regexp).