create type from pattern matching in scala - scala

I'm new using Scala and what I need is to create like a dynamic type based on some pattern matching function, like
type defType = "value1" match {
case "value0" => typeOf[String]
case "value1" => typeOf[Integer]
case _ => typeOf[Double]
}
val test5 : defType = 4
This is just an example given that I'd to work with more complex structures, but gives the idea of what I want to do.

I probably don't understand what you're doing, but this seems problematic to me:
val test5 : defType = 4
The compiler needs to be able to know defType at compile time, otherwise it can't type check. Based on that, I think what you want to do is do this pattern matching at compile time by utilizing Scala macros.
However, I have a feeling that's not the right solution either just because this whole scenario seems very strange. If you give more detail about what the bigger picture is of what you're trying to do maybe we can suggest a better solution.

I fear this is not possible, for fundamental conceptual reasons. As type rules are checked at compile time, it is not possible to derive types based on values that might be unknown until runtime.
That being said, you might be able to tackle your design problem by defining a family of case classes, each being a wrapper for a value of a specific type. By giving these classes a common base class, you can store a value of any type you wish into the same variable and extract it through type-safe pattern matching:
class Base
case class AString(val value: String) extends Base
case class AnInt(val value: Int) extends Base
case class ADouble(val value: Double) extends Base
val a : Base = "value1" match {
case "value0" => AString(…)
case "value1" => AnInt(…)
case "value0" => ADouble(…)
}
a match {
case AString(s) => …
case AnInt(i) => …
case ADouble(i) => …
…
}

Related

What is the meaning of the word "case" in scala's "case class"?

I understand that case class causes the compiler to augment a class with boilerplate to implement a certain useful pattern ("plain and immutable data-holding objects that should exclusively depend on their constructor arguments").
But the word "case" itself has no meaning to me in this context. I'm accustomed to its use as part of switch statements in C#, but that seems to have no relevance to Scala's use of the word.
I find it easier to program when I can attach words to particular meanings. Right now my mental model is case => boilerplate, in the same way that it could be blurg => boilerplate. It's a working mental model, but ambiguity makes it easy to misunderstand or to forget altogether.
So what does the word case have to do with what the compiler actually does?
I'm not looking for "what was in the mind of the designers" but rather "what's a rational way to relate this term to its meaning, given general knowledge of the language's design."
In my opinion, the term case comes from case analysis which is a reasoning technique enabled by special structures called algebraic data types. By itself case in case class might not make much sense, but when it forms a part of a sealed structure, which is how Scala defines ADTs, for example
sealed trait Number
case object Zero extends Number
case class Succ(v: Number) extends Number
then we see there are two forms of constructing Numbers, namely using Zero and Succ constructors. Hence whenever we have to think about Numbers, we at least know there are two different cases to consider. For example, say we want to define addition on Numbers, then its definition will have to handle two cases, perhaps, like so
def sum(a: Number, b: Number): Number =
a match {
case Zero => b
case Succ(v) => Succ(sum(v, b))
}
where
sum(Succ(Zero), Succ(Zero)) == Succ(Succ(Zero)) // 1 + 1 = 2
sum(Succ(Succ(Zero)), Succ(Zero)) == Succ(Succ(Succ(Zero))) // 2 + 1 = 3
sum(Succ(Zero), Succ(Succ(Zero))) == Succ(Succ(Succ(Zero))) // 1 + 2 = 3
sum(Zero, Succ(Succ(Zero))) == Succ(Succ(Zero)) // 0 + 2 = 2
sum(Succ(Succ(Zero)), Zero) == Succ(Succ(Zero)) // 2 + 0 = 2
Note how Scala in order to define ADT uses terms like class, object, trait etc., which appear to be from the object-oriented paradigm, however ADTs conceptually have little in common with class hierarchies found in OO. Personally I find this confusing, but we must remember Scala is both functional and OO language, which might be a reason for such terminological spillover. In some other more "pure" languages case class of ADT is represented simply by a vertical bar |, say like so
Inductive nat : Type :=
| O : nat
| S : nat -> nat.
My suggestion would be to try not to be a "slave to words" but instead words should serve you. What is important is the meaning behind the words or terms, not the words themselves. Do not build mental models around the terms, instead build mental models around the heavy concepts they are struggling to carry across feeble bridges of communication. In my opinion, the concept case is trying to communicate is that of ADT.
C# has a switch / case language feature which allows controlling program flow by matching an input to a set of possible values.
public static GetEmail(string name)
{
switch (name)
{
case "bill":
return "bill#example.com";
case "jane":
return "jane#example.com";
default:
return null;
}
}
Here, case roughly means "in the case that the given value is equal to this one, do X."
Scala's match / case feature is sort of like C#'s feature.
def getEmail(name: String): Option[String] = {
name match {
case "bill" => Option("bill#example.com")
case "jane" => Option("jane#example.com")
case _ => None
}
}
But it's much more powerful. It is designed to evaluate "matches" against things farm more complex than strings. To take advantage of this powerful matching feature, you define immutable data-holding classes with case class.
Here is a trivial, but hopefully helpful, example of a case class and its use with match / case:
case class Person(name: String, hasEmail: Boolean)
object EmailHelper {
def getEmail(person: Person): Option[String] = {
person match {
case Person(_, false) => None
case Person("bill", true) => Option("bill#example.com")
case Person("jane", true) => Option("jane#example.com")
case _ => None
}
}
}
In short, case class enforces a set of constraints which make a class usable with match / case.

It is possible to define Scala case objects programmatically?

In my current project, I need to define a lot of case objects subclassing a single sealed trait. The names of these objects have a pattern, e.g., Case1, Case2, Case3, ..., CaseN. I was wondering if there is way in scala to define all these case objects in a programmatical way, for example with a loop, instead of writing N lines of definitions.
If this is feasible, it would also be great to do this at compile time so that the case objects defined in this way are known to type checking. This sounds impossible in most languages (you can have either dynamically defined types like in python or have static type safety like in C/C++, but not both), but maybe it is doable in Scala for its powerful compile-time reflection?
I'm thinking about this solution:
trait customTrait{
val property: String
}
case class toMatch(property: String) extends customTrait{
}
val cases: Seq[toMatch] = for{
x <- 0 until 10
} yield toMatch("property" + x)
def matchCase(caseToMatch: customTrait): String = caseToMatch match{
case toMatch("property1") => "1"
case toMatch("property2") => "2"
case toMatch("property3") => "3"
case toMatch("property4") => "4"
case _ => "non"
}
for {
x <- cases
} yield matchCase(x)

Selector of pattern match being exhaustive

Looking at the Scala doc for sealed classes, it says:
If the selector of a pattern match is an instance of a sealed class, the compilation of pattern matching can emit warnings which diagnose that a given set of patterns is not exhaustive, i.e. that there is a possibility of a MatchError being raised at run-time.
I don't quite understand what they meant in this paragraph. My understanding is that if a switch case, doesn't cover all the possibilities, then we'll get a warning at compile time, saying we might get an error at run time. Is this correct?
I find it strange, because how can we cover ALL the scenarios in a switch case? We would have to match all possible strings, which is just silly, so I take it my understanding is incorrect. Someone care to elucidate, please?
What the paragraph is saying is that in-case you have a fixed hierarchy structure like this:
sealed trait Foo
class Bar extends Foo
class Baz extends Foo
class Zab extends Foo
Then when you pattern match on it, the compiler can infer if you've attempted to match on all possible types extending the sealed trait, in this example:
def f(foo: Foo) = foo match {
| case _: Bar => println("bar")
| case _: Baz => println("baz")
| }
<console>:13: warning: match may not be exhaustive.
It would fail on the following input: Zab()
def f(foo: Foo) = foo match {
^
f: (foo: Foo)Unit
Note the beginning of the document says:
A sealed class may not be directly inherited, except if the inheriting
template is defined in the same source file as the inherited class.
This is unique to Scala, and can't be done in Java. A final class in Java cannot be inherited even if declared inside the same file. This is why this logic won't work for String in Scala, which is an alias for java.lang.String. The compiler warning may only be emitted for Scala types that match the above criteria.
I find it strange, because how can we cover ALL the scenarios in a switch case? We would have to match all possible strings
Yes, if the selector has type String (except it isn't a sealed class, because that's a Scala concept and String is a Java class).
which is just silly
No. For strings, you just need a catch-all case, e.g.
val x: String = ...
x match {
case "a" => ...
case "b" => ...
case _ => ...
}
is an exhaustive match: whatever x is, it matches one of the cases. More usefully, you can have:
val x: Option[A] = ...
x match {
case Some(y) => ...
case None => ...
}
and the compiler will be aware the match is exhaustive even without a catch-all case.
The wildcard character allows us to cover all the scenarios.
something match {
case one => ...
case two => ...
case _ => ...
}
It is selected whenever all other cases don't match; that is, it is the default case. Further information here.

Implicits over type inference for object transformation

Part of a current project involves converting from types coupled to a database and a generic type used when serializing the results out to clients via Json, the current implementation in Scala uses type inference to correctly perform the transformation, using Scala's TypeTag:
def Transform[A: TypeTag](objects:Seq[A]):Seq[Children] = typeOf[A] match {
case pc if pc =:= typeOf[ProductCategory] =>
TransformProductCategory(objects.asInstanceOf[Seq[ProductCategory]])
case pa if pa =:= typeOf[ProductArea] =>
TransformProductArea(objects.asInstanceOf[Seq[ProductArea]])
case pg if pg =:= typeOf[ProductGroup] =>
TransformProductGroup(objects.asInstanceOf[Seq[ProductGroup]])
case psg if psg =:= typeOf[ProductSubGroup] =>
TransformProductSubGroup(objects.asInstanceOf[Seq[ProductSubGroup]])
case _ =>
throw new IllegalArgumentException("Invalid transformation")
}
The types used as input are all case classes and are defined internally within the application, for example:
case class ProductCategory(id: Long, name: String,
thumbnail: Option[String],
image:Option[String],
sequence:Int)
This approach, although suitable at the moment, doesn't feel functional or scalable when potentially more DB types are added. I also feel using asInstanceOf should be redundant as the type has already been asserted. My limited knowledge of implicits suggests they could be used instead to perform the transformation, and remove the need for the above Transform[A: TypeTag](objects:Seq[A]):Seq[Children] method altogether. Or maybe there is a different approach I should have used instead?
You can define a trait like this:
trait Transformer[A] {
def transformImpl(x: Seq[A]): Seq[Children]
}
Then you can define some instances:
object Transformer {
implicit val forProduct = new Transformer[ProductCategory] {
def transformImpl(x: Seq[ProductCategory]) = ...
}
...
}
And then finally:
def transform[A: Transformer](objects:Seq[A]): Seq[Children] =
implicitly[Transformer[A]].transformImpl(objects)
Preferably, you should define your implicit instances either in Transformer object or in objects corresponding to your category classes.
I'm not sure how your program is supposed to work exactly, nor do I know if any of your Transforms are self-made types or something you pulled from a library, however I may have a solution anyway
Something match is really good with, is case classes
So rather than manually checking the type of the input data, you could maybe wrap them all in case classes (if you need to bring data with you) or case objects (if you don't)
That way you can do something like this:
// this code assumes ProductCategory, ProductArea, etc.
// all extends the trait ProductType
def Transform(pType: ProductType): Seq[Children] = pType match {
case ProductCategory(objects) => TransformProductCategory(objects)
case ProductArea(objects) => TransformProductArea(objects)
case ProductGroup(objects) => TransformProductGroup(objects)
case ProductSubGroup(objects) => TransformProductSubGroup(objects)
}
By wrapping everything in a case class, you can specify exactly which type of data you want to bring along, and so long as they (the case classes, not the data) all inherit from the same class/trait, you should be fine
And since there's only a little handful of classes that extend ProductType you don't need the default case, because there is no default case!
Another benefit of this, is that it's infinitely expandable; just add more cases and case classes!
Note that this solution requires you to refactor your code a LOT, so bare that in mind before you throw yourself into it.

How to pattern match multiple values in Scala?

Let's say I want to handle multiple return values from a remote service using the same code. I don't know how to express this in Scala:
code match {
case "1" => // Whatever
case "2" => // Same whatever
case "3" => // Ah, something different
}
I know I can use Extract Method and call that, but there's still repetition in the call. If I were using Ruby, I'd write it like this:
case code
when "1", "2"
# Whatever
when "3"
# Ah, something different
end
Note that I simplified the example, thus I don't want to pattern match on regular expressions or some such. The match values are actually complex values.
You can do:
code match {
case "1" | "2" => // whatever
case "3" =>
}
Note that you cannot bind parts of the pattern to names - you can't do this currently:
code match {
case Left(x) | Right(x) =>
case null =>
}
The other answer correctly says that currently there is no way to pattern-match multiple alternatives while extracting values at the same time.
I'd like to share a coding pattern with you that comes close to doing this.
Scala allows you to pattern-match alternatives without extracting values, e.g. case Dog(_, _) | Cat(_, _) => ... is legal. Using this, you can simply extract the values yourself within the case block.
Here's a somewhat contrived example:
abstract class Animal
case class Dog(age: Int, barkLevel: Int) extends Animal
case class Cat(apparentAge: Int, cutenessLevel: Int) extends Animal
val pet: Animal = Dog(42, 100)
// Assume foo needs to treat the age of dogs and the apparent age
// of cats the same way.
// Same holds for bark and cuteness level.
def foo(pet: Animal): Unit = pet match {
case animal#(Dog(_, _) | Cat(_, _)) =>
// #unchecked suppresses the Scala warning about possibly
// non-exhaustiveness even though this match is exhaustive
val (agelike, level) = (animal: #unchecked) match {
case Dog(age, barkLevel) => (age, barkLevel)
case Cat(apparentAge, cutenessLevel) => (apparentAge, cutenessLevel)
}
???
}
Assume that ??? actually stands for doing something that is equal for dogs and cats. Without this coding pattern, you would need to have two cases, one for dogs and one for cats, forcing you to duplicate code or at least to outsorce code into a function.
Generally, the coding pattern above is suitable if you have sibling case classes that share fields that behave identically only for some algorithms. In those cases, you cannot extract those fields to a common superclass. Still, you would like to pattern-match in a uniform way on those fields in the algorithms that treat them equally. This you can do as shown above.