How do I acquire shapeless.Generic[T] instances properly - scala

I'm getting my feet wet in generic programming with Shapeless and I'm running into usual beginner problems.
I actually wrote a piece of code that applies a polymorphic function to case classes that compiles and works correctly under Scala IDE but fails to compile under sbt. While trying to minimize the issue I came all the way down the basic example in https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/generic.scala and my problems with creating Generic instances still persisted.
I'd really appreciate an explanation why this compiles:
object Example {
sealed class Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
val generic = shapeless.Generic[Animal]
}
while this:
sealed class Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
object Example {
val generic = shapeless.Generic[Animal]
}
and this:
sealed class Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
object Animal {
val generic = shapeless.Generic[Animal]
}
fails to compile with:
could not find implicit value for parameter gen: shapeless.Generic[example.Example.Animal]
not enough arguments for method apply: (implicit gen: shapeless.Generic[example.Example.Animal])shapeless.Generic.Aux[example.Example.Animal,gen.Repr] in object Generic. Unspecified value parameter gen.
I'm using shapeless 2.3.0 with Scala 2.11.8.
Thanks is advance!

Related

toString method for inherited case class in Scala

I am facing some inconsistency in calling toString method for case-classes in Scala. The first code sample:
case class Person(name: String, age: Int)
val jim = Person("jim", 42)
println(jim)
output: Person(jim,42)
For the next code sample I used a case class that extends Exception:
case class JimOverslept(msg: String) extends Exception
try {
throw JimOverslept(msg = "went to bed late")
} catch {
case e: JimOverslept => println(e)
}
output: playground.CaseClassOutput$JimOverslept
Actually, I would prefer the output like JimOverslept(went to bed late)
What is the reason the both outputs are so different? And what is the best way to obtain the output looks like desired one (JimOverslept(went to bed late))
According to SLS 5.3.2 Case Classes
Every case class implicitly overrides some method definitions of class
scala.AnyRef unless a definition of the same method is already given
in the case class itself or a concrete definition of the same method
is given in some base class of the case class different from AnyRef.
Now toString is already provided by base class in
case class JimOverslept(msg: String) extends Exception
where Exception extends base Throwable which provides toString definition. Hence try providing an override within the case class itself like so
case class JimOverslept(msg: String) extends Exception {
override def toString: String = scala.runtime.ScalaRunTime._toString(this)
}

Generic enum using case class in scala

I have created the following enum objects
sealed trait MsgMapping[T] {def mycode: T;}
object Type1 {
sealed trait msg[Int] extends MsgMapping[Int]
case object A extends msg[Int]{val myCode = 0;}
case object B extends msg[Int]{val myCode = 1;}
}
object Type2 {
sealed trait msgtype[String] extends MsgMapping[String]
case object C extends msgtype[String]{val myCode = "xyz";}
case object D extends msgtype[String]{val myCode = "def";}
}
I want to create a generic case class that can except any type of MessageMapping ,it can be an Integer/String or any data type
But this line gives error as it expects the type.
case class EumType(valueType: MsgMapping [T])
The below works
case class EumType1(valueType: MsgMapping [Int])
case class EumType2(valueType: MsgMapping [String])
case class TestEnum(value:EumType1)
case class Test(val:TestEnum)
But I do not want to create EumType1 and EumType2 .Can anyone help to me to create a generic code for this
Update
As per suggestion
case class EnumType[T](valueType: MsgMapping[T])
case class TestEnum(value:EnumType[T])
It will throw compile error since it expects type
here but i want to pass the type on this line
case class Test(val:TestEnum) ,whether it is Type1 /Type2
Try using an existential type:
case class EumType(valueType: MessageMapping [_])

Difference between using sealed trait and sealed abstract class as a base class

While trying to learn Akka, I often find examples with a class hierarchy similar to this:
sealed trait Message
case class TextMessage(user: String, text: String) extends Message
case class StatusMessage(status: String) extends Message
However, in the Scala docs there's a following example:
abstract class Notification
case class Email(sourceEmail: String, title: String, body: String) extends Notification
case class SMS(sourceNumber: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
What's the difference in using a sealed trait vs. an abstract class (or sealed abstract class in this case) as a base class without constructor parameters for a class hierarchy? Are there some advantages in using one over the other?
Edit:
Specifically, if both, the trait and the abstract class are sealed, I can't extend them outside the file, right? In that case I couldn't inherit from them in Java either? If that's the case, being sealed would render most of the arguments found in the suggested duplicate useless since they refer to inheritance outside the file.
In this particular case there are no differences except that you can't extend multiple abstract classes but you can extend multiple traits.
You should check other answers (as mentioned in the comments) to see the actual differences between abstract classes and traits. If you are just going to use an abstract class or a trait to define the type hierarchy as in this case, then there are no differences.
E.g. you could to the following:
trait A
trait B
case class C(a: Int) extends A with B
but you can't do:
abstract class A
abstract class B
case class C(a: Int) extends A with B

Generate constructor for superclass in Scala

Given simple class hierarchy
abstract sealed class Base(id: String)
case class Child1(id: String, value: Int) extends Base(id)
case class Child2(id: String, value: Long, file: File) extends Base(id)
can I use macros or something like that to avoid passing id to Base (and instruct compiler to generate this for me)? With single argument it's not that hard to pass it, but in case of several arguments it becomes uncomfortable.
Or if I could omit specification of id in child classes and make compiler generating ones for me from base class?
You can make Base as a trait:
sealed trait Base {
val id: String
}
case class Child1(id: String, value: Int) extends Base
case class Child2(id: String, value: Long, file: File) extends Base

Scala: lock extended class

I'd like to "lock" a class, which is extended from a trait. Is it possible in Scala?
For example I have:
trait A {
val boris: String
val john: String
val number: Int
}
class B extends A {
// do something with these values
}
but can I ensure, that in class B no new values will be added if those aren't declared in trait A?
Thanks for your answers.
You cannot.
But if you simply mark the trait as sealed and provide a default implementation:
sealed trait A { val boris: String }
final class B(val boris: String) extends A {}
then people are free to create implicit value classes that make it look like new functionality has been added (except without actually creating the class):
implicit class MyB(val underlying: B) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B("fish")).sirob // "hsif"
You can also let the classes take a type parameter as a marker if you want to keep them straight at compile-time (though not runtime):
sealed trait A[T] { val boris: String }
final class B[T](val boris: String) extends A[T] {}
implicit class MyB(val underlying: B[Int]) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B[Int]("fish")).sirob // "hsif"
(new B[Char]("fish")).sirob // error: value sirob is not a member of B[Char]
So you could--especially with 2.10--simply lock everything and let users enrich the original interface this way.
I'm not sure if this covers your intended use case, though; it doesn't provide any inheritance.
Based on your example and my guess at what you are actually trying to do, you may want to consider just using case classes.
Extending a case class is generally avoided (I think it will spit out deprecation warnings if you try), so that will prevent people from wanting to extend your class in order to add functionality.
Translating your example into a case class:
case class A (boris: String, john: String, number: Int)
Then instead of extending A to change its values, you'd just make a new instance, e.g.
val a2 = someOtherA.copy(john="Doe")