I am not able to access the class constructor parameter in the body of the function. In Scala the constructor parameter becomes the class member with appropriate get/set defined.
But in the below example, i am not able to refer to the constructor parameter 'p'. Is there something i am doing wrong? do i need to put a prefix?
abstract class MyFunc(in: Int) extends Function1[Int, Boolean] {
val x : Int = 10
}
val dunc = new MyFunc(10) {
def apply(p: Int): Boolean = {
p % in == 0 << compilation error. 'in' value not found
// p % x == 0 << compiles fine
}
}
I am able to access an explicitly defined member variable but not the constructor defined variable. Why?
By default constructor parameters are private: so they are visible only in class itself. But you change this behaviour:
abstract class MyFunc(protected val in: Int) extends Function1[Int, Boolean] {
val x : Int = 10
}
Related
I have a Scala code similar to the code below. There is an implicit defined at the class / object level and I want to 'override' it with an implicit defined in the method. (If you really need to know, I need to change my ExecutionContext specially for the method in question).
In this example, I want to use b as the implicit for Int in the scope of the bar method. How can I do this?
object Foo {
implicit val a: Int = 1
def bar: Int = { // Didn't pass implicit Int parameter
implicit val b: Int = 2
implicitly[Int]
}
}
This complains with
error: ambiguous implicit values:
both value a in object Foo of type Int
and value b of type Int
match expected type Int
So I think Scala cannot choose between the class-scope implicit and method-scope implicit.
In dotty/scala 3 that should already work as you intended (second bullet point). In Scala 2 you have to shadow the implicit in the outer scope by giving them the same name.
object Foo {
implicit val a: Int = 1
def bar: Int = {
implicit val a: Int = 2
implicitly[Int] // 2
}
}
That's the strategy that was used in the implementation of the Scala 3 compiler, when it was compiled with Scala 2: http://dotty.epfl.ch/docs/internals/contexts.html#using-contexts
You can`t do this in the current Scala 2. At least without unclear approaches (hacks) like shadowing.
Because there is no difference between method scope or class member scope or code block scope. You have only two scopes - the local scope and the scope of corresponding types. You can read about there (Implicit Scope and Implicit Resolution).
What you can do to achieve wanted results?
You can move your code into another scope. E.g. a newly created static object.
object Foo {
implicit val a: Int = 1
val b: Int = 2
def bar: Int = AnotherScopeObject.bar(b)
}
object AnotherScopeObject {
def bar(implicit implicitInt: Int) : Int = {
implicitly[Int]
}
}
I am defining an abstract class taking a type parameter, along with several concrete classes which set this type.
abstract class GenericFoo[T: ClassTag] {
def defaultValue: T
def useTheValue(v: T): T
}
object DoubleFoo extends GenericFoo[Double] {
def defaultValue = 42.0
def useTheValue(v: Double) = v * 2
}
object IntFoo extends GenericFoo[Int] {
def defaultValue = 1337
def useTheValue(v: Int) = v + 64
}
But when storing my Foos in a mixed collection, it seems that my type parameter T always ends up being inferred up to Any.
val fooCollection:List[GenericFoo[_]] = List(DoubleFoo, IntFoo)
for {
foo <- fooCollection
defaultValue = foo.defaultValue
result = foo.useTheValue(defaultValue)
// Error: `defaultValue` has type `Any`, cannot call `useTheValue`
} yield result
Based on several answers to similar questions, I thought using type parameter wildcard (GenericFoo[_]), and maybe ClassTag would help keep type information, but I couldn't get this example to work as I wanted.
In the snippet above, I would want foo.defaultValue to be recognized as having the correct type (T) to be applicable in foo.useTheValue(). Have I missed something?
Edit: #gzm0 was prompt to suggest that I use abstract type members. My original use-case was a little more involved, as I am also defining an abstract type for a companion object. My actual code does something similar to:
trait GenericCompanion[T] {
// Some "static" members
def defaultValue: T
def useTheValue(v: T): T
}
abstract class GenericFoo[T] {
def getCompanion: GenericCompanion[T]
// Because of this operation, it's important that we have the same type `T`
def useCompanion: T = getCompanion.useTheValue(theActualValue)
val theActualValue: T
}
object ConcreteCompanion[Double] extends GenericCompanion[Double] {
// ...
}
object ConcreteFoo[Double] extends GenericFoo[Double] {
def getCompanion = ConcreteCompanion
}
Each concrete implementation of GenericFoo[T] also comes with a CompanionFoo[T]. Concrete sub-classes of GenericFoo are supposed to instantiated, while CompanionFoo[T] objects are here to hold "static" properties and operations. In this context, it is very important that the type parameter in GenericFoo is the same as the type parameter in GenericCompanion.
(I hope this is clear enough, sorry if my example is convoluted!)
This is a vanilla example for abstract type members. Try this:
abstract class GenericFoo {
type V
def defaultValue: V
def useTheValue(v: V): V
}
object DoubleFoo extends GenericFoo {
type V = Double
def defaultValue = 42.0
def useTheValue(v: Double) = v * 2
}
object IntFoo extends GenericFoo {
type V = Int
def defaultValue = 1337
def useTheValue(v: Int) = v + 64
}
val fooCollection:List[GenericFoo] = List(DoubleFoo, IntFoo)
Rest of the code remains unchanged.
If you use an abstract type member (rather than a type parameter), Scala will take track of the concrete types it knows for a given value.
From your example explained:
val foo: GenericCollection = ???
val defaultValue = foo.defaultValue
// defaultValue: foo.V
foo.useTheValue(defaultValue)
// foo.useTheValue: (foo.V): foo.V
Although the compiler does not know what true type foo.V is, it can nevertheless figure out that the type signatures match and that using calling useTheValue with defaultValue is OK.
As far as I can tell, this would also be a perfectly OK reasoning with type parameters, Scala just does not do it.
UPDATE
You can still do this, even with the more involved example:
trait GenericCompanion {
type T
// Some "static" members
def defaultValue: T
def useTheValue(v: T): T
}
abstract class GenericFoo { self =>
type T
def getCompanion: GenericCompanion { type T = self.T }
// Because of this operation, it's important that we have the same type `T`
def useCompanion: T = getCompanion.useTheValue(theActualValue)
val theActualValue: T
}
And the concrete implementations:
object ConcreteCompanionDouble extends GenericCompanion {
type T = Double
def defaultValue: Double = ???
def useTheValue(v: Double): Double = ???
// ...
}
object ConcreteFooDouble extends GenericFoo {
type T = Double
def getCompanion = ConcreteCompanionDouble
val theActualValue: Double = ???
}
Is it possible to write something like this and reuse the HelperTest.AnyHelper type?
class HelperUtil
{
/* this is what I would like to write... reuse the AnyHelper type in the definition */
def accept[HelperTest.AnyHelper](helper : HelperTest.AnyHelper) =
{
// code here
}
}
object HelperTest
{
type AnyHelper = T forSome { type T <: GenericHelper }
}
abstract class GenericHelper
{
val name = ""
}
Currently I am forced to write this, since the compiler won't let me:
class HelperUtil
{
/* gets too verbose, if the generic type gets more complex and would be useful to reuse the type */
def accept[T <: GenericHelper](helper : T) =
{
// code here
}
}
abstract class GenericHelper
{
val name = ""
}
Or am I completely on the wrong track?
I guess you are mistaken about how type parameters in a signature such as def accept[T] work. The type variable T in this signature gets bound, that is, T is introduced as a new type variable. If there already exists a type variable with the same name in the current context, then it will be shadowed by the newly bound T. Consider this example:
class Foo[T] {
def id[T](t: T) = t
}
The class signature binds a new T that can be referred to in the class body. However, the method signature binds a T as well, which shadows the class T. With the result, that you can instantiate the class T with some type X and the method T with some other type Y:
val f = new Foo[String]
f.id(0)
Back to your code. Your signature
def accept[HelperTest.AnyHelper](helper : HelperTest.AnyHelper)
thus tries to bind a new type variable HelperTest.AnyHelper - which the compiler rejects, because type variables may not contain a dot (.).
Do the following instead:
import scala.language.existentials
trait A
class B1 extends A
class C1 extends B1
class B2 extends A
object HelperUtil {
type MyA = T forSome { type T <: A }
}
class HelperUtil {
/* Reuse type declaration */
def foo(a: HelperUtil.MyA) = println(a.getClass.getName)
def bar(a: HelperUtil.MyA) = println(a.getClass.getName)
def baz(a: HelperUtil.MyA) = println(a.getClass.getName)
}
val hu = new HelperUtil
/* Instantiate with different types */
hu.foo(new B1) // B1
hu.foo(new B2) // B2
hu.bar(new C1) // C1
Section 4.6.2 of the Scala Language Specification Version 2.8 describes repeated parameters and says:
The last value parameter of a parameter section may be suffixed by “*”, e.g. (..., x:T*). The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T].
However, this code:
abstract class A { def aSeq : Seq[A] }
class B(val aSeq : A*) extends A
class C extends B { override val aSeq :Seq[A] = Seq() }
give an error when compiled:
overriding value aSeq in class B of type A*; value aSeq has incompatible type
The compiler seems to indicate that A* is a distinct type from Seq[A].
Investigating the actual class of aSeq in this case shows it to be an instance of scala.collection.mutable.WrappedArray$ofRef but even the following code fails to compile with the same message:
class C extends B { override val aSeq = new ofRef(Array[A]()) }
So the question is, how do I go about overriding a member defined by a repeated parameter on the class?
In case you're wondering where this is coming from, that is exacly what scala.xml.Elem does to override the child method in scala.xml.Node.
Your issue can be summarized as:
scala> class A { def aSeq(i: Int*) = 1 }
defined class A
scala> class B extends A { override def aSeq(i: Seq[Int]) = 2 }
<console>:6: error: method aSeq overrides nothing
class B extends A { override def aSeq(i: Seq[Int]) = 2 }
The methods have different types. The spec says (emphasis mine):
The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T]
As Int* and Seq[Int] aren't inside the method, this particular sentence does not apply.
Interestingly, this following code shows that the methods have different types before erasure but the same after:
scala> class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 }
<console>:5: error: double definition:
method aSeq:(i: Seq[Int])Int and
method aSeq:(i: Int*)Int at line 5
have same type after erasure: (i: Seq)Int
class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 }
So the question then becomes, why your B class can extend your A abstract class. There may be an inconsistency in the spec there. I don't know...
Edit: I re-read the spec and I can't figure out if there is anything related to repeated parameters and overriding. There does not seem to be anything about return type of repeated parameters, which is what you get for the val aSeq accessor method.
I think Mark's answer is a perfectly valid approach. In case you can't follow it, you can use the following workaround:
class C extends B {
private def aSeqHelper(a: A*) = a
override val aSeq = aSeqHelper(Seq[A](): _*)
}
So for instance:
import scala.xml._
class ElemX extends Elem("pref", "label", <xml a="b"/>.attributes, TopScope) {
private def childHelper(c: Node*) = c
override val child = childHelper(<foo/><bar/>: _*) }
Then:
scala> new ElemX
res4: ElemX = <pref:label a="b"><foo></foo><bar></bar></pref:label>
The copy method of xml.Elem uses it like this
def copy(
prefix: String = this.prefix,
label: String = this.label,
attributes: MetaData = this.attributes,
scope: NamespaceBinding = this.scope,
child: Seq[Node] = this.child.toSeq
): Elem = Elem(prefix, label, attributes, scope, child: _*)
So you can override the value in the B constructor
class C extends B(aSeq = Seq(): _*)
Or declare it as a parameter of the class C
class C(seq: Seq[A]) extends B(aSeq = seq: _*)
Though I am not sure it answers your question!
The spec never allowed for repeated types to leak out in this way. The compiler was changed in July 2011 to enforce this.
For more background, check out the comments in the ticket:
https://issues.scala-lang.org/browse/SI-4176
In Scala, how does one define a local parameter in the primary constructor of a class that is not a data member and that, for example, serves only to initialize a data member in the base class?
For example, in the following code, how could I properly define parameter b in the primary constructor of class B so that it generates only a temporary local parameter and not a data member?
class A(var a: Int)
class B(?b?) extends A(b)
Randall, your answers explain why the Scala compiler complains when I introduce a method inc that increments the property a, but also change the name of the parameter in the class B constructor to match that of the parameter in the class A constructor:
class A(var a: Int)
class B(a: Int) extends A(a) {
def inc(value: Int) { this.a += value }
}
Scala compiler output:
$ scala construct.scala
construct.scala:3: error: reassignment to val
def inc(value: Int) { this.a += value }
^
one error found
Scala complains because class B must now have a private, read-only property a due to the reference to a in inc. Changing B(a: Int) to B(var a: Int) generates a different compiler error:
construct.scala:2: error: error overriding variable a in class A of type Int;
variable a needs `override' modifier
class B(var a: Int) extends A(a) {
^
one error found
Adding override doesn't help, either:
construct.scala:2: error: error overriding variable a in class A of type Int;
variable a cannot override a mutable variable
class B(override var a: Int) extends A(a) {
^
one error found
How can I use the same name in the parameter in the primary constructor of B as the property defined in the primary constructor of the base class A?
If you remove the "var" or "val" keyword from the constructor parameter, it does not produce a property.
Be aware, though, that non-var, non-val constructor parameters are in-scope and accessible throughout the class. If you use one in non-constructor code (i.e., in the body of a method), there will be an invisible private field in the generated class that holds that constructor parameter, just as if you made it a "private var" or "private val" constructor parameter.
Addendum (better late than never??):
In this code the references to the constructor parameter occur only in the constructor body:
class C1(i: Int) {
val iSquared = i * i
val iCubed = iSquared * i
val iEven = i - i % 2
}
... Here the value i exists only during the execution of the constructor.
However, in the following code, because the constructor parameter is referenced in a method body—which is not part of the constructor body—the constructor parameter must be copied to a (private) field of the generated class (increasing its memory requirement by the 4 bytes required to hold an Int):
class C2(i: Int) {
val iSquared = i * i
val iCubed = iSquared * i
val iEven = i - i % 2
def mod(d: Int) = i % d
}
After some experimentation, I determined that simply leaving out var or val in front of the parameter b will make it a local parameter and not a data member:
class A(var a: Int)
class B(b: Int) extends A(b)
Java expansion:
$ javap -private B
Compiled from "construct.scala"
public class B extends A implements scala.ScalaObject{
public B(int);
}
$ javap -private A
Compiled from "construct.scala"
public class A extends java.lang.Object implements scala.ScalaObject{
private int a;
public A(int);
public void a_$eq(int);
public int a();
public int $tag() throws java.rmi.RemoteException;
}
Notice that class A has a private data member a due to the var a: Int in its primary constructor. Class B, however, has no data members, but its primary constructor still has a single integer parameter.
You can create temporary variables throughout the initialization of single class members like this:
class A(b:Int){
val m = {
val tmp = b*b
tmp+tmp
}
}
Derek,
If you have this:
class A(a: Int) {
val aa = a // reference to constructor argument in constructor code (no problem)
def m: Float = a.toFloat // reference to constructor argument in method body (causes a to be held in a field)
}
you'll find (using javap, e.g.) that a field named "a" is present in the class. If you comment out the "def m" you'll then see that the field is not created.