How can a parameter's default value reference another parameter? - scala

How can a parameter's default value reference another parameter? If it cannot, how to work around that?
case class A(val x:Int, val y:Int = x*2)
Error (reasonably enough):
scala> case class B(val x:Int, val y:Int = x*2)
<console>:7: error: not found: value x
case class B(val x:Int, val y:Int = x*2)
^

This requires that you use multiple parameter lists:
case class A(x: Int)(y: Int = x*2)
Default values can only refer to parameters in preceding lists.
Be careful however with case classes, because their equality only takes into the account the first parameter list, therefore:
A(1)() == A(1)(3) // --> true!!

Since you asked for the work-around, if it's not obvious how to preserve caseness:
scala> :pa
// Entering paste mode (ctrl-D to finish)
case class Foo(x: Int, y: Int)
object Foo {
def apply(x: Int): Foo = apply(x, 2*x)
}
// Exiting paste mode, now interpreting.
defined class Foo
defined object Foo
scala> Foo(5,6)
res45: Foo = Foo(5,6)
scala> Foo(5)
res46: Foo = Foo(5,10)

Related

Scala: implicitly to implicit class

Given:
implicit class Foo(val i: Int) {
def addValue(v: Int): Int = i + v
}
is it possible apply to it any implicitly?
I get an error here:
<console>:14: error: could not find implicit value for parameter e: Foo
implicitly[Foo]
An implicit class Foo(val i: Int) means that there is an implicit conversion from Int to Foo. So implicitly[Int => Foo] should work.
Think about it like this: if you could summon a Foo with implicitly[Foo], which Foo would you expect to get? A Foo(0)? A Foo(1)? A Foo(2)?
For further details,
implcitly key word can be explained as following
implitly[T] means return implicit value of type T in the context
Which means, to get Foo implicitly you need to create an implicit value in the scope
For example,
implicit class Foo(val i: Int) {
def addValue(v: Int): Int = i + v
}
implicit val foo:Foo = Foo(1)
val fooImplicitly = implicitly[Foo] // Foo(1)
Also, note that Foo itself is only a class,
But by putting implicit key word in front of class definition,
Compiler creates an implicit function of type Int => Foo

default type conversions from sub to supertype, zero parameter functions

I am trying to understand the mechanism with which scala implements default type converions from sub to super type in scala.Predef. From the literature I gathered that this is done with the function
implicit def conforms[A] = new A<:<A { def apply(a:A)=a }
The parameterless function conforms[A] returns the implicit conversion A=>B as its only
function value (as a callable of type A=>A and thus of type A=>B, whenver A<:B).
However when the compiler looks for an implicit type conversion it needs an implicit value
of type A=>B not a function returning such a value. Thus my question:
When looking for a default type conversion from A=>B, where A<:B, how does the compiler
get from the function conforms[A] to its unique value.
The implicit resolution seeks for subtypes too, A <: B => A => A <: A => B, as in List[Int] <: Seq[Int].
scala> :paste
// Entering paste mode (ctrl-D to finish)
implicit val x: List[Int] = List(1, 2, 3)
def f(implicit x: Seq[Int]): Int = x.head
f
// Exiting paste mode, now interpreting.
x: Seq[Int] = List(1, 2, 3)
f: (implicit x: Seq[Int])Int
res1: Int = 1
So when making type conversion we look for A => B with A <: B, and A => A fits.
I'm not sure if I understood you right, but the defs are followed while searching for value of the needed type. It doesn't matter whether function takes zero, one, or more parameters. For example with zero:
implicit def implicitList[A]: List[A] = List() //the only obvious case
scala> implicitly[Seq[Int]]
// res0: Seq[Int] = List()
Or two:
case class Foo(str: String)
case class Bar(str: String)
case class Quux(str: String)
implicit val foo = Foo("foo")
implicit val bar = Bar("bar")
// how to build quux:
implicit def quux(implicit foo: Foo, bar: Bar): Quux = Quux(foo.str + bar.str)
implicitly[Quux]
// res2: Quux = Quux(foobar)
If we add any of:
implicit def quux2(implicit quux: Quux): Quux = quux
implicit def quux3(implicit foo: Foo): Quux = Quux(foo.str)
implicit val quux4: Quux = Quux("quux")
implicit def quux5[A]: Quux = Quux("poly")
We make implicit resolution undecidable for Quux:
scala> implicitly[Quux]
<console>:29: error: ambiguous implicit values:
both method quux of type (implicit foo: Foo, implicit bar: Bar)Quux
and method quux2 of type (implicit quux: Quux)Quux
match expected type Quux
implicitly[Quux]
^
I.e. there could be only one def or val in scope returning the type we are interested. And that is easy to verify statically.
But they will work if any of those is the only one in scope.

Implicit Resolution with Contravariance

Given classes Parent and Child.
scala> class Parent
defined class Parent
scala> class Child extends Parent
defined class Child
Define implicits for Parent and Child
scala> implicit val a = new Parent
a: Parent = Parent#5902f207
scala> implicit val b = new Child
b: Child = Child#3f7d8bac
Use implicitly to find out which implicit gets resolved.
scala> implicitly[Child]
res1: Child = Child#3f7d8bac
illustration of my understanding:
Parent
|
Child -- implicit resolution gets the most specific, lowest sub-type
Now, let's use a contravariant type.
scala> trait A[-T]
defined trait A
scala> case class Concrete[T]() extends A[T]
defined class Concrete
Then define a Parent and Child class.
scala> class Parent
defined class Parent
scala> class Kid extends Parent
defined class Kid
Create implicits for them too.
scala> implicit val x = Concrete[Parent]
x: Concrete[Parent] = Concrete()
scala> implicit val y = Concrete[Kid]
y: Concrete[Kid] = Concrete()
scala> implicitly[A[Parent]]
res1: A[Parent] = Concrete()
scala> implicitly[A[Kid]]
<console>:21: error: ambiguous implicit values:
both value x of type => Concrete[Parent]
and value y of type => Concrete[Kid]
match expected type A[Kid]
implicitly[A[Kid]]
^
In the first example (without contravariance), Scala was able to resolve the implicit Child for implicitly[Parent]. It seems to me that it's picking the lowest sub-type.
However, when using contravariance, the behavior changes. Why?
Your implicits are typed Concrete and that is invariant here.
Try either
case class Concrete[-T]() extends A[T]
or
implicit val x: A[Parent] = Concrete[Parent]
More words:
Implicits (values or views) should have an explicit type so you're never surprised by the inferred type. Picking the implicit is all about the type.
It picks one of your implicits using the same rules as the overloading resolution conversion that is used to pick alternatives of an overloaded symbol.
For simple values (not function calls), that comes down to conformance or subtyping.
There is also the rule that a definition in a "derived type" (usually a subclass) is preferred.
Here is a test you can do using only commonly available household materials:
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> trait A[-T]
defined trait A
scala> case class Concrete[T](i: Int) extends A[T]
defined class Concrete
scala> class Parent ; class Kid extends Parent
defined class Parent
defined class Kid
// it will pick X if X isAsSpecific as Y but not conversely
scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]])
res0: Boolean = false
scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]])
res1: Boolean = false
scala> case class Concrete[-T](i: Int) extends A[T]
defined class Concrete
scala> typer.infer.isAsSpecific(typeOf[Concrete[Kid]],typeOf[Concrete[Parent]])
res2: Boolean = false
scala> typer.infer.isAsSpecific(typeOf[Concrete[Parent]],typeOf[Concrete[Kid]])
res3: Boolean = true
Edit:
Another view of why it matters what type you're testing:
scala> trait A[-T]
defined trait A
scala> case class Concrete[T](i: Int) extends A[T] // invariant
defined class Concrete
scala> class Parent ; class Kid extends Parent
defined class Parent
defined class Kid
scala> implicitly[Concrete[Parent] <:< Concrete[Kid]]
<console>:13: error: Cannot prove that Concrete[Parent] <:< Concrete[Kid].
implicitly[Concrete[Parent] <:< Concrete[Kid]]
^
scala> implicit val x: Concrete[Parent] = Concrete[Parent](3) // the inferred type
x: Concrete[Parent] = Concrete(3)
scala> implicit val y = Concrete[Kid](4)
y: Concrete[Kid] = Concrete(4)
// both values conform to A[Kid] (because A is contravariant)
// but when it puts x and y side-by-side to see which is more specific,
// it no longer cares that you were looking for an A. All it knows is
// that the values are Concrete. The same thing happens when you overload
// a method; if there are two candidates, it doesn't care what the expected
// type is at the call site or how many args you passed.
scala> implicitly[A[Kid]]
<console>:15: error: ambiguous implicit values:
both value x of type => Concrete[Parent]
and value y of type => Concrete[Kid]
match expected type A[Kid]
implicitly[A[Kid]]
^
Give them explicit types and the variance of Concrete won't matter. You always supply explicit types for your implicits, right? Just like retronym tells us to?
scala> implicit val x: A[Parent] = Concrete[Parent](3)
x: A[Parent] = Concrete(3)
scala> implicit val y: A[Kid] = Concrete[Kid](4)
y: A[Kid] = Concrete(4)
scala> implicitly[A[Kid]]
res2: A[Kid] = Concrete(3)

Scala class constructor default arguments with expression using previous members

I'd want to create a class (or better case class) which would behave like this:
case class MyClass(n: Int, m: Int = 2 * n)
So that m could have default value based on n. But seems it is impossible, scala says: not found: value n. First idea is to write m: Int = -1 and mutate it in constructor if it's still -1, but it is val. And now I have no any other ideas.
Maybe anybody will shed some light on what's possible here?
You can explicitly provide a second factory:
case class MyClass(n: Int, m: Int)
object MyClass{
def apply(n: Int): MyClass = MyClass(n, 2 * n)
}
Unlike when using 2 parameter lists as in #om-nom-nom's answer, the case class is unaffected, and in particular you can pattern match as usual to extract both n and m.
You must define a companion object :
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class MyClass(n: Int, m: Int);
object MyClass {
def apply(n: Int) : MyClass = new MyClass(n, n * 2)
}
// Exiting paste mode, now interpreting.
defined class MyClass
defined module MyClass
scala> MyClass(12);
res4: MyClass = MyClass(12,24)

Adding a field to Scala case class?

I've seen some blogs on the Pimp my Library pattern, and these seem to work well for adding behavior to classes.
But what if I have a case class and I want to add data members to it? As a case class I can't extend it (inheriting from a case class is deprecated/strongly discouraged). Will any of these pimp patterns allow me to add data to a case class?
No - I don't see how you could make this work because the enriched instance is usually thrown away (note: newly the pimp-my-library pattern is called enrich-my-library). For example:
scala> case class X(i: Int, s: String)
defined class X
scala> implicit class Y(x: X) {
| var f: Float = 0F
| }
defined class Y
scala> X(1, "a")
res17: X = X(1,a)
scala> res17.f = 5F
res17.f: Float = 0.0
scala> res17.f
res18: Float = 0.0
You would have to make sure you kept hold of the wrapped instance:
scala> res17: Y
res19: Y = Y#4c2d27de
scala> res19.f = 4
res19.f: Float = 4.0
scala> res19.f
res20: Float = 4.0
However, I find this not useful in practice. You have a wrapper; you're better off making this explicit
This is not the way to do. Just a proof of possibility. With this way you can get plenty of problems.
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class A(i: Int)
class B(a: A){
var s: String = ""
}
object B{
val as = scala.collection.mutable.WeakHashMap[A, B]()
}
implicit def a2b(a: A) = B.as.getOrElseUpdate(a, new B(a))
// Exiting paste mode, now interpreting.
defined class A
defined class B
defined module B
a2b: (a: A)B
scala> val a = A(1)
a: A = A(1)
scala> a.s = "test"
scala> a.s
res0: String = test
WeakHashMap: A hash map with references to entries which are weakly reachable. Entries are removed from this map when the key is no longer (strongly) referenced. This class wraps java.util.WeakHashMap.
Note that due to case class's overridden equals method you get this funny behavior:
scala> A(2).s = "test2"
scala> A(2).s
res2: String = test2
so you should not use case class or use it with override def equals(that: Any) = this eq that.asInstanceOf[AnyRef].