import scala.reflect.ClassTag
class IntStorage {
var variable: Int = 5
}
class testing[T : ClassTag] {
var example = Array.ofDim[T](10, 10)
def testFunc(): Int = example(0)(0).variable
}
Error: value variable is not a member of T
I do not understand why I get this error, even though I use a Classtag.
The ClassTag is fine. But you declared testing to work for any class, not just IntStorage. What if I call new testing[String]()? String is a perfectly valid class with a class tag, but it doesn't have a variable field. I could call it with any class.
Is it possible you meant
class testing[T <: IntStorage : ClassTag] { ... }
Related
In the following example, is there a way to avoid that implicit resolution picks the defaultInstance and uses the intInstance instead? More background after the code:
// the following part is an external fixed API
trait TypeCls[A] {
def foo: String
}
object TypeCls {
def foo[A](implicit x: TypeCls[A]) = x.foo
implicit def defaultInstance[A]: TypeCls[A] = new TypeCls[A] {
def foo = "default"
}
implicit val intInstance: TypeCls[Int] = new TypeCls[Int] {
def foo = "integer"
}
}
trait FooM {
type A
def foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
def foo: String = implicitly[TypeCls[A]].foo
}
class MyFooP extends FooP[Int]
class MyFooM extends FooM { type A = Int }
object Main extends App {
println(s"With type parameter: ${(new MyFooP).foo}")
println(s"With type member: ${(new MyFooM).foo}")
}
Actual output:
With type parameter: integer
With type member: default
Desired output:
With type parameter: integer
With type member: integer
I am working with a third-party library that uses the above scheme to provide "default" instances for the type class TypeCls. I think the above code is a minimal example that demonstrates my problem.
Users are supposed to mix in the FooM trait and instantiate the abstract type member A. The problem is that due to the defaultInstance the call of (new MyFooM).foo does not resolve the specialized intInstance and instead commits to defaultInstance which is not what I want.
I added an alternative version using type parameters, called FooP (P = Parameter, M = Member) which avoids to resolve the defaultInstance by using a context bound on the type parameter.
Is there an equivalent way to do this with type members?
EDIT: I have an error in my simplification, actually the foo is not a def but a val, so it is not possible to add an implicit parameter. So no of the current answers are applicable.
trait FooM {
type A
val foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
val foo: String = implicitly[TypeCls[A]].foo
}
The simplest solution in this specific case is have foo itself require an implicit instance of TypeCls[A].
The only downside is that it will be passed on every call to foo as opposed to just when instantiating
FooM. So you'll have to make sure they are in scope on every call to foo. Though as long as the TypeCls instances are in the companion object, you won't have anything special to do.
trait FooM {
type A
def foo(implicit e: TypeCls[A]): String = e.foo
}
UPDATE: In my above answer I managed to miss the fact that FooM cannot be modified. In addition the latest edit to the question mentions that FooM.foo is actually a val and not a def.
Well the bad news is that the API you're using is simply broken. There is no way FooM.foo wille ever return anything useful (it will always resolve TypeCls[A] to TypeCls.defaultInstance regardless of the actual value of A). The only way out is to override foo in a derived class where the actual value of A is known, in order to be able to use the proper instance of TypeCls. Fortunately, this idea can be combined with your original workaround of using a class with a context bound (FooP in your case):
class FooMEx[T:TypeCls] extends FooM {
type A = T
override val foo: String = implicitly[TypeCls[A]].foo
}
Now instead of having your classes extend FooM directly, have them extend FooMEx:
class MyFoo extends FooMEx[Int]
The only difference between FooMEx and your original FooP class is that FooMEx does extend FooM, so MyFoo is a proper instance of FooM and can thus be used with the fixed API.
Can you copy the code from the third party library. Overriding the method does the trick.
class MyFooM extends FooM { type A = Int
override def foo: String = implicitly[TypeCls[A]].foo}
It is a hack, but I doubt there is anything better.
I do not know why this works the way it does. It must be some order in which the type alias are substituted in the implicitly expression.
Only an expert in the language specification can tell you the exact reason.
I can't understand why I need () and hence where MyTypeQueOrdering goes.
Here is header of PriorityQueue, found on official github:
class PriorityQueue[A](implicit val ord: Ordering[A])
Here is my try (which works):
class MyType{
}
object MyTypeQueOrdering extends Ordering[MyType]{
def compare (n1:MyType, n2:MyType) = -1
}
class MyTypeQue extends PriorityQueue[MyType]()(MyTypeQueOrdering){
}
... but I can't figure out why I need (). Does PriorityQueue[MyType]() return something?
Try making MyTypeQueOrdering an implicit object:
object Implicits {
//implicit objects can't be top-level ones
implicit object MyTypeQueOrdering extends Ordering[MyType] {
def compare(n1: MyType, n2: MyType) = -1
}
}
This way you can omit both parentheses:
import Implicits._
class MyTypeQue extends PriorityQueue[MyType] { ... }
The reason you need the empty parentheses in your example is because PriorityQueue[MyType](MyTypeQueOrdering) would assume you're trying to pass the ordering as a constructor parameter. So that's why you need to explicitly show no-arg instantiation and then passing the ordering
Why does Scala behave like this ?
More importantly, how can this code be fixed ?
I am asking this question because I have complicated types that I need to use in constructor declarations in several subclasses and I want to stay DRY.
class Parent{
type IntAlias=Int
}
class Child (val i1:IntAlias=3) extends Parent{ //Compilation error, why ?
val i2:IntAlias= 1 //No problem here!
}
Compiler error:
not found: type IntAlias
class Child (val i1:IntAlias=3) extends Parent{
^
In your definition, IntAlias is a member of class Parent. So without an instance of Parent you cannot access that member. You can read your second case as val i2: this.IntAlias = 1. Here you have access to the instance this.
This is similar to the following for values instead of types:
class Parent {
def intValue: Int = 1234
}
class Child(val x: Int = intValue) extends Parent // does not compile
So you must put that member in a different scope, for example a companion object:
object Parent {
type IntAlias = Int
}
import Parent.IntAlias
class Child(val i1: IntAlias = 3) extends Parent {
val i2: IntAlias = 1
}
Why do I have to do
trait Compiler {
var printInstruction: String
}
class JavaCompiler extends Compiler {
var printInstruction = "System.out.print(arg0);"
}
instead of
trait Compiler {
var printInstruction: String
}
class JavaCompiler extends Compiler {
printInstruction = "System.out.print(arg0);"
}
when
trait Compiler {
var printInstruction: String
def printInstruction: String
}
gives compile error.
Because you don't initialize the variable in trait Compiler. It means that you expect that anyone who extends Compile defines something that behaves like a variable.
For example the following is valid:
class Example extends Compiler {
var _printInstruction = "foo"
def pritnInstruction = "I don't care about setter"
def pritnInstruction_=(pi: String) = _printInstruction = pi
}
If you want to be able to use
class JavaCompiler extends Compiler {
printInstruction = "System.out.print(arg0);"
}
Then initialize your var in the Compilertrait:
trait Compiler {
var printInstruction: String = _
}
Overriding vars is generally not something you want to do. If you want something that behaves like a var, and may even be one, you do this:
trait Compiler {
def printInstruction: String
def printInstruction_=(s: String): Unit
}
class JavaCompiler {
var printInstructions = "System.out.print(arg0);"
}
Somehow I don't think that's what you intended. So... what don't you explain what you actually intend to accomplish, so we can better advise on how to do it?
I have a base class with some constructor parameter:
abstract class HugeClass(implicit context: ContextClass) {
...
}
Because the class gets bigger and bigger and only some subclasses need some special behaviour, I want to refactor it into a trait. However, I still need access to context in the trait. I tried this:
trait SomeTrait extends HugeClass {
def myMethod = {
context.method
}
}
But the scala compiler says: not found: value context. How can I solve that?
Parameter context is turned into a private field. The fact that a parameter or a member is implicit does not mean it is public - it is implicit only within the class it is visible in (HugeClass).
Turn context into a val:
abstract class HugeClass(implicit val context: ContextClass) {
...
}
and it will work.