Overloading constructor in generic scala class - scala

I'm trying to overload a constructor in a generic scala class but it's not compiling.
Here's my code:
class V[T](m: Map[T,Double]) {
def this(dt: Seq[Double]) = this(dt.zipWithIndex.map(_.swap).toMap)
}
And the error messages I get:
ERROR: called constructor's definition must precede calling constructor's definition : line 6
ERROR: overloaded method constructor V with alternatives:
(dt: Seq[Double])V[T] <and> (m: Map[T,Double])V[T] cannot be applied to
(scala.collection.immutable.Map[Int,Double]) : line 6
As far as I understand constructor overloading in scala, I think I'm following the proper syntax and the restriction that the call to this should precede everything else.
So what am I doing wrong and how can I fix this?

With
def this(dt: Seq[Double]) = this(dt.zipWithIndex.map(_.swap).toMap)
You're creating a new map Map[Int,Double]; Int being the type of the index created by zipWithIndex.
If T were Int, then you can use the constructor (m:Map[T,Double].
However: T is not yet bound to a type since you're defining the class. Nor will the type matching bind T to Int at this point.
Therefore the type matching fails.
Solutions:
How to fix it depends on what you're trying to do.
If it were the case that T <: Int, then bounding the type-param with <: Int could resolve your problem; however it seems a bit unlikely that T is a subclass of Int...
If it is always true that T : Int, then drop the generic T.
If T is to remain generic and unbounded then that leaves you with making a special case for when T : Int; senia's solution looks good for that.

You can fix it with companion object:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class V[T](m: Map[T,Double])
object V{
def apply(dt: Seq[Double]) = new V[Int](dt.zipWithIndex.map(_.swap)(collection.breakOut))
}
// Exiting paste mode, now interpreting.
defined class V
defined module V
scala> V(Seq(1.,2.,3.))
res0: V[Int] = V#1130e2ea

Related

What does Scala mean by Suspicious Type Shadowing?

I'm implementing a scala Set, and I'm getting this error from this code
Suspicious shadowing by a Type Parameter: A
def remove[A](elemToRemove: A): MySet[A]
^
which for some reason, the language hates this generic A I'm passing it, why is that? and what does it mean by "Suspicious shadonwing"?
https://scastie.scala-lang.org/NwcMObgnSxGjXA2clmaEyA, though scastie is running into a different error, if you remove the [A] from remove[A] it will pass and execute
type mismatch;
found : exercises.part2afp.MySet[A(in class NonEmptySet)]
required: exercises.part2afp.MySet[A(in method remove)]
This is the context:
case class EmptySet[A]() extends MySet[A] {
override def remove[A](elemToRemove: A): MySet[A] = this
The problem is that the A in remove[A] is a different type from the A in EmptySet[A].
If you want these to be different types, use different letters.
If it is supposed to be the same type, delete the [A] from remove.

Implicit conversions weirdness

I am trying to understand why exactly an implicit conversion is working in one case, but not in the other.
Here is an example:
case class Wrapper[T](wrapped: T)
trait Wrapping { implicit def wrapIt[T](x: Option[T]) = x.map(Wrapper(_))
class NotWorking extends Wrapping { def foo: Option[Wrapper[String]] = Some("foo") }
class Working extends Wrapping {
def foo: Option[Wrapper[String]] = {
val why = Some("foo")
why
}
}
Basically, I have an implicit conversion from Option[T] to Option[Wrapper[T]], and am trying to define a function, that returns an optional string, that gets implicitly wrapped.
The question is why, when I try to return Option[String] directly (NotWorking above), I get an error (found : String("foo") required: Wrapper[String]), that goes away if I assign the result to a val before returning it.
What gives?
I don't know if this is intended or would be considered a bug, but here is what I think is happening.
In def foo: Option[Wrapper[String]] = Some("foo") the compiler will set the expected type of the argument provided to Some( ) as Wrapper[String]. Then it sees that you provided a String which it is not what is expected, so it looks for an implicit conversion String => Wrapper[String], can't find one, and fails.
Why does it need that expected type stuff, and doesn't just type Some("foo") as Some[String] and afterwards try to find a conversion?
Because scalac wants to be able to typecheck the following code:
case class Invariant[T](t: T)
val a: Invariant[Any] = Invariant("s")
In order for this code to work, the compiler can't just type Invariant("s") as Invariant[String] because then compilation will fail as Invariant[String] is not a subtype of Invariant[Any]. The compiler needs to set the expected type of "s" to Any so that it can see that "s" is an instance of Any before it's too late.
In order for both this code and your code to work out correctly, I think the compiler would need some kind of backtracking logic which it doesn't seem to have, perhaps for good reasons.
The reason that your Working code does work, is that this kind of type inference does not span multiple lines. Analogously val a: Invariant[Any] = {val why = Invariant("s"); why} does not compile.

Build List of Foo's with Specific Value at Compile-Time

Given:
case class Foo(x: BigDecimal)
I'd like to, at compile-time, build a List[Foo] where each Foo must have a BigDecimal value of 5.
So, I'd expect the following code to compile:
type Foo5Only = ???
val foos5: List[Foo5Only] = List(Foo(5), Foo(5))
But, I'd expect the following to fail to compile:
val bad: List[Foo5Only] = List(Foo(42))
I'm speculating that a shapeless Singleton type might be useful, but I don't actually understand it.
Note - I'm not interested, for this question, in an answer that results in using Either or Option.
As well as using shapeless' Nat type you could also use singleton types. Unfortunately Scala's built-in List type has covariance which gets in the way of type safety, but using a simple hand-crafted list type seems to work:
import shapeless.syntax.singleton._
sealed trait Lst[T]
case class Nil[T]() extends Lst[T]
case class Cons[T](head : T, tail : Lst[T]) extends Lst[T]
def list[T](t : T) : Lst[T] = {
Cons(t, Nil())
}
// OK
val foos5 = Cons(5.narrow, list(5.narrow))
// Compile-time type mismatch error.
val foos6 = Cons(42.narrow, list(5.narrow))
You might be able to elide the narrows with some macro-magic, but that's beyond my ability.

overloaded method value apply with alternatives

I have the following code:
case class A[T](a:T, b:Array[Int])
object A {
def apply[T](aa:T):A[T] = A(aa, Array(1, 2, 3))
}
trait TLike[T]
case class TSample1[T](str:String) extends TLike[T]
Why if I instantiate from A with type I get the following error:
object tmp extends App{
val a = A[TLike[TSample1]](TSample1("dumb"))
}
Error:
overloaded method value apply with alternatives:
(a: TLike[TSample1],b: Array[Int])A[TLike[TSample1]] <and>
(aa: TLike[TSample1])A[TLike[TSample1]]
cannot be applied to (TSample1[Nothing])
val a = A[TLike[TSample1]](TSample1("dumb"))
But if I just leave it to Scalac it works correctly:
object tmp extends App{
val a = A(TSample1("dumb"))
}
If we start with your case that compiles, you call object A's apply method, which works as expected.
If we later go to the example that doesn't compile and look at the compile error:
Main.scala:10: error: overloaded method value apply with alternatives:
(a: TLike[TSample1],b: Array[Int])A[TLike[TSample1]] <and>
(aa: TLike[TSample1])A[TLike[TSample1]]
cannot be applied to (TSample1[Nothing])
val a = A[TLike[TSample1]](TSample1("dumb"))
^
one error found
It says that it finds two apply methods, one which you defined and one which is the standard case class method (read more about that if you need to).
I'm guessing you try to call this method:
def apply[T](aa:T):A[T] = A(aa, Array(1, 2, 3))
However you can't call the A object's apply function with a template. The other call doesn't match since it also needs an array. Also the types TLike[TSample1] is not equal to TSample1.
Actually it's hard to understand what you are trying to achieve here, but you should consider two things:
TSample take arguments, so Tlike[TSample] is pretty complex type
as there no hints in parameters in for TSample.apply what type parameter T should be, it would be inferred to Nothing by default
This for example would compile
A[TLike[TSample1[_]]](TSample1[TSample1[_]]("dumb"))
Whis would also:
A[TLike[Nothing]](TSample1("dumb"))
Latter is equivalent for
A(TSample1("dumb"))
without any type specification

Reify a ValDef from compile to runtime

I want to reify a ValDef into runtime, but i does not work directly. If i encapsulate the ValDef into a Block, everything works perfectly, like in the following example:
case class Container(expr: Expr[Any])
def lift(expr: Any): Container = macro reifyValDef
def reifyValDef(c: Context)(expr: c.Expr[Any]): c.Expr[Container] = {
import c.universe._
expr.tree match {
case Block(List(v: ValDef), _) =>
val asBlock = q"{$v}"
val toRuntime = q"scala.reflect.runtime.universe.reify($asBlock)"
c.Expr[Container](q"Container($toRuntime)")
}
}
lift {
val x: Int = 10
}
If i would use v directly, instead of wrapping it into a block, I get the error:
Error:(10, 11) type mismatch;
found :
required: Any
Note that extends Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
val x: Int = 10
^
Is it just not working directly with ValDefs or is something wrong with my code?
That's one of the known issues in the reflection API. Definitions are technically not expressions, so you can't e.g. pass them directly as arguments to functions. Wrapping the definition in a block is a correct way of addressing the block.
The error message is of course confusing, but it does make some twisted sense. To signify the fact that a definition by itself doesn't have a type, the tpe field of the corresponding Tree is set to NoType. Then the type of the argument of a macro is checked against Any and the check fails (because NoType is a special type, which isn't compatible with anything), so a standard error message is printed. The awkward printout is an artifact of how the prettyprinter behaves in this weird situation.