Is it possible to define value class in scala for some Numeric[T]? I tried something like this:
case class Inches[T <: Numeric[T]](value: T)(implicit num: Numeric[T]) extends AnyVal
However I get compilation error that value classes can have only one parameter.
Is there any way to bypass this?
Thanks beforehand.
You can move the Numeric parameter from class to the methods which require it:
case class Inches[T](value: T) extends AnyVal {
def foo()(implicit num: Numeric[T]) = ...
}
(T <: Numeric[T] is wrong.)
Related
Does AnyVal (Int, Double) extend scala.Serializable and what is the different between java.io.Serializable and scala.Serializable as a method parameter in Scala?
def f (p : scala.Serializable): Unit = {}
def g (p : java.io.Serializable): Unit = {}
//f(1) Type mismatch, expected:Serializable,actual:Int
g(1) //It works
The Scala doc says that Int is a subType of scala.Serializable(http://www.scala-lang.org/api/2.10.6/index.html#scala.Serializable).However,scala.Serializable extends java.io.Serializable. so I think the value of Int is kind type of scala.Serializable and java.io.Serializable and both can be the parameter above.
Thanks.
Actually Int does not extend Serializable. The link (from known subclasses) is this one which is just an Ordering[Int] implicit instance. Int and AnyVal are defined like so:
final abstract class Int private extends AnyVal
abstract class AnyVal extends Any
So as you can see, they're not java.io.Serializable or scala.Serializable.
As for why the code works, check out scala.Predef to find the implicit conversion from scala.Int to java.lang.Integer (which implements java.io.Serializable). And scala.Predef is imported implicitly so that's why it works:
object Predef {
...
implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x)
...
}
So behind the scene your code is the following:
g(1)
// After the implicit conversion g(1) is actually:
g(Integer.valueOf(1))
I hope this clears up the confusion, I've been there myself :)
I have defined the following class hierarchy where I want to restrict the the type parameter to be conformable with Double...
sealed abstract class Quantity[-T](value: T)(implicit ev: T <:< Double)
case class DiscreteQuantity(value: Long) extends Quantity[Long](value)
case class ContinuousQuantity(value: Double) extends Quantity[Double](value)
...is it possible to re-write the above hierarchy so that the concrete types are value classes? From the docs I know that value classes can not be extended, so that rules out having Quantity inherit from AnyVal. In order for concrete classes to inherit from AnyVal I need to make Quantity a trait, which is fine, but then I lose the contra-variant annotation on the type parameter.
Thoughts?
It is possible, but as I said in the comment: <:< and <: don't include weak conformance, so basically only Quantity[Double] can exist.
sealed trait Quantity[-T <: Double] extends Any {
protected[this] def value: T
}
case class ContinuousQuantity(value: Double) extends AnyVal with Quantity[Double]
I am writing a program in scala that uses a framework around:
trait Tool[T <: Tool[T, U], U <: Settings[T]] {
// members here
def createSettingsFrom(settingsWithStringNames: Map[String, _]): U
}
trait Settings[T <: Tool[T, _ <: Settings[T]]
In Tool, T is the subclass, and U is a class that carries information for it. Each Tool can be regarded as a sort of command with parameters, and those parameters are custom for each of them.
I also have a class that extends it, along with its "information carrier":
object Cleanup extends Tool[Cleanup, CleanupSettings] {
override def createSettingsFrom(settings: Map[String, _]): CleanupSettings
= CleanupSettings(
settings.get("attribute1").asInstanceOf[Int]
settings.get("attribute2").asInstanceOf[String])
}
case class CleanupSettings extends Settings[Cleanup](
//attribute1: Int,
//attribute2: String
//more attributes)
When I attempt to compile these classes, I get the following stacktrace:
Information:21/10/16 03:20 - Compilation completed with 2 errors and 0 warnings in 3s 200ms
/project_folder/src/main/scala/io/oreville/maptools/operations/cleanup/Cleanup.scala
Error:(17, 24) type arguments [package.tools.operations.cleanup.Cleanup,package.tools.operations.cleanup.CleanupSettings] do not conform to trait ConfigurableTool's type parameter bounds [T <: package.tools.ConfigurableTool[T,U],U <: package.tools.params.Settings[T]]
object Cleanup extends ConfigurableTool[Cleanup, CleanupSettings] {
^
/project_folder/src/main/scala/io/oreville/maptools/operations/cleanup/CleanupSettings.scala
Error:(11, 11) type arguments [package.tools.operations.cleanup.Cleanup] do not conform to trait Settings's type parameter bounds [T <: package.tools.Tool[T, _ <: package.tools.params.Settings[T]]]
extends Settings[Cleanup]
^
I also have a trait ConfigurableTool which is just an extension of Tool with some extra functionality, so it has the exact same generic signature and it just extends Tool[T, U].
I tried multiple things to solve the problem including adding combinations of + and - to my generics for co- and contravariance, but it doesn't help.
I did consider using a Dynamic type for my settings, but speed is a bit of a factor. I don't even know if it would solve the problem if I did.
That's it really, I hope that you have some time to help my case, if not, thanks for reading anyway!
I wan't able to reproduce the error message you got.
There are a few typos in the code, but after cleaning them up, the only error left is in the definition of Cleanup which you cannot pass as a type parameter when extending a trait.
object Cleanup extends Tool[Cleanup.type, CleanupSettings] { ... }
illegal cyclic reference involving object Cleanup
You can get around that by making it a trait, and extending it in the companion object. Here's the full code:
trait Tool[T <: Tool[T, U], U <: Settings[T]] {
// members here
def createSettingsFrom(settingsWithStringNames: Map[String, _]): U
}
trait Settings[T <: Tool[T, _ <: Settings[T]]]
trait Cleanup extends Tool[Cleanup, CleanupSettings] {
override def createSettingsFrom(settings: Map[String, _]): CleanupSettings = CleanupSettings(
settings.get("attribute1").asInstanceOf[Int],
settings.get("attribute2").asInstanceOf[String])
}
object Cleanup extends Cleanup
case class CleanupSettings(
attribute1: Int,
attribute2: String) extends Settings[Cleanup]
While this compiles:
implicit class Container[T](val value:T) extends AnyVal{
def addInt(x:Int)(implicit ev:T=:=Int) = value+x
}
This complains about type mismatch, expected T, actual Int, as if it ignores the type bound.
implicit class Container[T](val value:T=>Int) extends AnyVal{
def addInt(x:Int)(implicit ev:T=:=Int) = value(x)
}
Why?
Your type constraint is backwards, actually. T =:= Int provides implicit evidence that T is Int, but not exactly that Int is T. If you look at the declaration if =:=, you'll see that it only goes one way:
sealed abstract class =:=[From, To] extends (From => To) with Serializable
Your first example works because value is a T, and the constraint is T =:= Int, which implicitly converts T to Int. But for the second example, we need to feed a T to value: T => Int, so we need the other direction.
This works:
implicit class Container[T](val value: T => Int) extends AnyVal {
def addInt(x: Int)(implicit ev: Int =:= T) = value(x)
}
The reason why your second example using Int <:< T also works is because <:< provides the implicit conversion from Int => T.
Oh probably the issue is the contra-variance of the function. This works now:
implicit class Container[T](val value:T=>Int) extends AnyVal{
def addInt(x:Int)(implicit ev:Int<:<T) = value(x)
}
I am working with trees and lists of expressions (Exp, members removed for brevity).
sealed abstract class Exp
abstract class BinaryExp extends Exp
case class Add extends BinaryExp
Most of the time I use pattern matching to process a tree or list of expressions.
But sometimes this is a bit tedious and I want to be able to write:
if (exp.isBinary) ...
//or
exps.filter(_.isAdd) ...
But this would mean that I need to create all sorts of properties in Exp with an implementation like:
def isXXX = this.isInstanceOf[XXXExp]
My first attempt to make this generic does not work because of type erasure:
def is[T <: Exp] = this.isInstanceOf[T]
So I searched for a solution and found TypeTags:
http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html
Scala: What is a TypeTag and how do I use it?
Attempt with TypeTags does not work either:
sealed abstract class Exp {
// Cannot use isInstanceOf because of type erasure.
import reflect.runtime.universe._
def is[T <: Exp: TypeTag] = typeOf[this.type] <:< typeOf[T]
def as[T <: Exp] = asInstanceOf[T]
}
Is there a way in Scala to do this?
You can try Manifest (note that it is deprecated in 2.10).
sealed abstract class Exp {
def is[T <: Exp: Manifest] = implicitly[Manifest[T]].erasure.isInstance(this)
def as[T <: Exp] = asInstanceOf[T]
}
Example: http://ideone.com/47Q5W3