I have a question about Template parameters in Scala with Case Classes.
First working scenario then what I try to achive
object Test1 {
sealed trait Response
final case class StateResponse(state : Any) extend Response
}
abstract class Test1[STATE] {
def something() : Unit = {
...
}
}
Now if use this in the following
import Test1._
result match {
case StateResponse(state) => ...
case _ => ...
}
Everything works fine but probably see what disturbs me, 'Any' at StateResponse. Depending on the implementation class I would like to have concrete State Type then any so..
object Test1Impl {
sealed trait State
final case class Test1State(payload: Map[String, String])
}
class Test1Impl extends Test1[Test1State] {
}
as you might guess I can't use Template parameter in Test1 in Object Definition but I thought, if I define the case class in class definition, it might work....
object Test1 {
sealed trait Response
}
abstract class Test1[STATE] {
final case class StateResponse(state : STATE) extends Response
def something() : Unit = {
.....
}
}
now until now, Scala Compiler does not complain about anything but when I try
import Test1._
result match {
case StateResponse(state) => ...
case _ => ...
}
then it can't locate 'StateResponse' at case statement and 'Test1.StateResponse' is not helping, so I am doing something illegal, but what?
Or can you tell me how can I make this work?
Thx for answers....
One way is to make StateResponse generic rather than enclosing class
final case class StateResponse[STATE](state : STATE) extends Response
Otherwise, when you make Test1 generic, an instance of StateResponse starts to depend on an instance of Test1
val t = new Test1[Int] {} // you made Test1 abstract, so I had to write {}
val result = t.StateResponse(10)
result match {
case t.StateResponse(state) => println("1")
case _ => println("2")
}
or
import t._
val result = StateResponse(10)
result match {
case StateResponse(state) => println("1")
case _ => println("2")
}
Related
I have different case classes and objects for that case class, and I am trying to instantiate the class object and return that class.
case class KeySet(KeyID:String,KeyName:String,KeyType:String)
object KeySet{
def fromXml(node: scala.xml.Node):KeySet = {
//some operation
new KeySet(KeyID,KeyName,KeyType)
}
}
case class NodeSet(NodeID:String,NodeValue:String,NodeType:String,NodeKey:String,NodeLocation:String)
object NodeSet{
def fromXml(node: scala.xml.Node):NodeSet = {
//some operation
new KeySet(NodeID,NodeValue,NodeType,NodeKey,NodeLocation)
}
}
and I have a method to create an instance of a class and return class object.
def getConnectionDetails(connectionType:String) : Option[Class[_]]= {
connectionType match {
case "KeySet" => Some(() => {
val xml_cred= scala.xml.XML.loadString("xmlfile")
KeySet.fromXml(xml_cred)
})
case "NodeSet" => Some(() => {
val xml_cred= scala.xml.XML.loadString("xmlfile")
NodeSet.fromXml(xml_cred)
})
case _ => None
}
}
Here i am getting the error in Return type, each case will return different case class.
what would be the return type for this method?.
In this particular case, the only common ancestor between two case classes is AnyRef, hence the type which can be used as function result type. But, using AnyRef or Any is highly un-recommended practice, because of lost type safety.
Instead, what you need to dot is to form Sum Type, via using common sealed trait, like shown below:
sealed trait ConnectionDetails
case class KeySet(keyID: String, keyName: String, keyType: String) extends ConnectionDetails
case class NodeSet(nodeID: String, nodeValue: String, nodeType: String, nodeKey: String, nodeLocation: String) extends ConnectionDetails
def getConnectionDetails(connectionType:String) : Option[ConnectionDetails]= {
connectionType match {
case "KeySet" =>
val xml_cred= scala.xml.XML.loadString("xmlfile")
Some(KeySet.fromXml(xml_cred))
case "NodeSet" =>
val xml_cred= scala.xml.XML.loadString("xmlfile")
Some(NodeSet.fromXml(xml_cred))
case _ => None
}
}
So, in all other places you can do pattern match against ConnectionDetails and this will be safe.
Hope this helps!
HI I have a case when calling a method to use self. Now not sure the best practice to do this in Scala. I have created a example of how I'm doing it just wanted to ask is this the best way of doing so.
sealed trait Animal {
// match on self
final def speak(): Unit = {
this match {
case Cat(name) => println("spoken like a Cat named: " + name)
case Dog(name) => println("spoken like a Dog named: " + name)
case Pig(name) => println("spoken like a Pig named: " + name)
}
}
final def whoAmI(): Unit = {
this match {
case Cat(_) => println("I am a Cat")
case Dog(_) => println("I am a Dog")
case Pig(_) => println("Could be a Pig")
}
}
}
final case class Cat(name: String) extends Animal
final case class Dog(name: String) extends Animal
final case class Pig(name: String) extends Animal
If your requirement is only to know which sub-type is used, it can be accessed in a more straightforward manner with just this.getClass():
sealed trait Animal {
val name: String
final def speak(): Unit =
println(s"spoken like a ${this.getClass.getSimpleName} named: ${name}")
final def whoAmI(): Unit =
println(s"I am a ${this.getClass.getSimpleName}")
}
If all the implementing sub-types are characterized by a name, that would be convenient to declare an abstract val name: String, which will allow to access the field in speak().
For a use case like this the matchers are not the best option: for each implementing sub-type you have to add an entry in the matchers (may become difficult to maintain). I'd suggest using inheritance: if you have a behavior differentiated among the sub-types, declare an abstract method in the trait, call it from it, but its implementations should remain at sub-types level.
Yes, your use of pattern matching on this is correct.
Since your hierarchy is sealed, you know, that there will not be any new types to account for - otherwise you should have the _ => ... clause.
You can express your second case a bit simpler, since you dont care about the parameters, only about the type.
final def whoAmI(): Unit = {
this match {
case _:Cat => println("I am a Cat")
case _:Dog => println("I am a Dog")
case _:Pig => println("Could be a Pig")
}
}
Finally, this always refers to the innermost type. In case of nested inner classes, you might want to use an alias, like self:
trait Tweeter {
this: self => // reassign this into self, so it can be accessed from an inner class
I've been knocking myself out trying to use a companion object to instantiate one of a class's subtypes. It's not known at compile time which subclass will be instantiated. This is remarkably similar to an example found in Programming Scala starting on page 127. I've contrived an example here:
import scala.reflect.runtime.universe._
abstract class Animal
class Dog extends Animal { def bark = "woof" }
class Cat extends Animal { def meow = "meow" }
object Animal {
def apply(specify: String): Option[Animal] = {
specify match {
case "dog" => Some(new Dog)
case "cat" => Some(new Cat)
case _ => None
}
}
}
object Test extends App {
def getType[T: TypeTag](obj: T) = typeOf[T]
var dog = Animal("dog")
println(getType(dog))
}
This program prints out scala.Option[Animal]. I'd expect it to print out scala.Option[Dog]. Furthermore, if I attempt to add the line println(dog.bark) to the end of the Test object, it fails to compile. Is this simply impossible?
I've been poring over Scala reflection documentation, but it seems very dense and difficult. Furthermore, this seems to be exactly how the Programming Scala example works, so I can't imagine what I've done wrong here.
EDIT: This version doesn't have reflection and simply throws a compile-time error due to the wrong type.
abstract class Animal
class Dog extends Animal { def bark = "woof" }
class Cat extends Animal { def meow = "meow" }
object Animal {
def apply(specify: String): Option[Animal] = {
specify match {
case "dog" => Some(new Dog)
case "cat" => Some(new Cat)
case _ => None
}
}
}
object Test extends App {
var dog = Animal("dog")
println(dog.get.bark)
}
// $ scalac test.scala
// test.scala:17: error: value bark is not a member of Animal
// println(dog.get.bark)
// ^
// one error found
EDIT: Evidently this requires pattern matching to work out. Here is a working example, somewhat simplified.
abstract class Animal
class Dog extends Animal { def bark = "woof" }
class Cat extends Animal { def meow = "meow" }
object Animal {
def apply(specify: String): Animal = {
specify match {
case "dog" => new Dog
case "cat" => new Cat
}
}
}
object Test extends App {
val dog = Animal("dog")
dog match {
case d: Dog => println(d.bark)
case _ =>
}
}
It is impossible.
In the second example, Animal.apply always returns Option[Animal], because that is its type signature.
Your object Test is really saying, expanded out a bit:
object Test extends App {
var dog: Option[Animal] = Animal.apply("dog")
println(dog.get.bark)
}
The compiler might be able to tell at compile time that it could be an Option[Dog], but the language's semantics don't allow for that: the grammar would have to be much more complex to be able to encapsulate that knowledge.
I have my case class:
case class MyClass(param : String)( body : => Unit) {
def save(){ ... }
def mymethod(){ ... }
body
save
}
then I want to use it like this:
MyClass("param"){ // this function can not see 'mymethod' ---
... |
mymethod() // <
...
}
Is there possible to make function 'body' be able to access 'mymethod'(and all others methods of class MyClass) ?
Why did you want this?
I see two possibilities:
Give your 'body' function a context argument:
case class MyClass(param : String)( body: MyClass => Unit) {
def mymethod() = println("MyClass.mymethod()")
body(this)
}
MyClass("test"){ ctx =>
ctx.mymethod()
}
or
Put your utility functions in MyClass companion object:
object MyClass {
def mymethod() = println("MyClass.mymethod()")
}
case class MyClass(param : String)( body: => Unit) {
body
}
MyClass("test"){
import MyClass._
mymethod()
}
Generically no. The usual approach to building a DSL is to use some kind of "command" objects, perhaps with the Free Monad:
object MyClass {
sealed trait Command
case class CallMyMethod() extends Command
def myMethod() = liftF[Command, Unit](CallMyMethod())
}
case class MyClass(param: String)(body: Free[Command, Unit]) {
...
body.resume.fold({
case CallMyMethod() => mymethod()
}, _ => {})
...
}
Then you can write your DSL "programs" using for/yield syntax:
import MyClass._
MyClass("param")({
for {
_ <- myMethod()
a = someNonMyClassCall()
b <- someOtherMyClassMethod(a)
} yield {}
})
Note that outside classes can create the CallMyMethod objects (since they're on the companion object), but that's fine, they "don't mean anything" until they're "interpreted" by the MyClass instance.
I am currently working on a E-Commerce application in scala / lift and cannot figure out how to match correctly on my type hierarchy. my current implementation is:
abstract trait BaseProduct[T <: BaseProduct[T]] extends MongoRecord[T] with ObjectIdPk[T] {
self:T =>
def whatever
...
}
abstract trait SimpleType[T <: BaseProduct[T]] extends BaseProduct[T] {
self:T =>
val producttype = "product/simple"
}
abstract trait ConfigurableType[T <: BaseProduct[T],E <: SimpleType[E]] extends BaseProduct[T] {
self: T =>
val producttype = "product/configurable"
}
class ClothingProduct extends SimpleType[ClothingProduct] {
def meta = ClothingProduct
}
class ConfigurableClothing extends ConfigurableType[ConfigurableClothing,ClothingProduct] {
val childmeta = ClothingProduct
val configurableFields = List(color,size)
def meta = ConfigurableClothing
}
With this in place I want to implement a Shopping Cart which should only take Products of Type SimpleType (and BaseProduct). It should also implement a function that takes any kind of BaseProduct with a pattern matching clause that should react to wheater it is a Simple or a Configurable Type.
My first implementations which drives me crazy due to Type Errors was:
object Cart extends SessionVar[List[CartItem]](List()) {
def addProduct(product:SimpleType[_],quantity:Int = 1) = {
this.get.partition(_.product.id.is == product.id.is) match {
case (Nil,xs) => this.set(CartItem(product,quantity) :: xs)
case (x,xs) => this.set(CartItem(product,x.head.quantity + quantity) :: xs)
}
}
}
case class CartItem(product:SimpleType[_], quantity:Int) {
def lineTotal:Double = quantity * product.price.is
}
With to following function to add a Cart Item:
def addBasketLink(prod:BaseProduct[_]) = {
prod match {
case x:SimpleType[_] => Cart.addProduct(x)
case _ => S.notice("Sorry not possible to add to Basket")
}
My main issue is that "Underscore" definition of the supplied type to SimpleType which causes type violation errors. I am currently not able to figure out how to do the wanted typing right. It would be great it someone could tell me where my error is and properbly explain to me how I work with typed traits correctly.
Thanks