In various Scala literature I see some self-type annotations using "this" and others using "self":
trait A { this: B => ... }
trait A { self: B => ... }
Is there any real difference between using "this" or "self"? Does it matter at all what name you use? Is this just as valid?
trait A { foo: B => ... }
All three forms are valid, and have the effect that B is assumed as the type of this in class A.
The first two variants
trait A { self: B => ... }
trait A { foo: B => ... }
introduce self (respectively, foo) as an alias for this in trait A. This is useful for accessing the this reference from an inner class. I.e. you could then use self instead of A.this when accessing the this reference of the trait A from a class nested within it. Example:
class MyFrame extends JFrame { frame =>
getContentPane().add( new JButton( "Hide" ) {
addActionListener( new ActionListener {
def actionPerformed( e: ActionEvent ) {
// this.setVisible( false ) --> shadowed by JButton!
frame.setVisible( false )
}
})
})
}
The third variant,
trait A { this: B => ... }
does not introduce an alias for this; it just sets the self type.
There is a difference in that this always refers to the object defined by the innermost template.
The expression this can appear in the statement part of a template or compound type. It stands for the object being defined by the innermost template or compound type enclosing the reference. If this is a compound type, the type of this is that compound type. If it is a template of a class or object definition with simple name C, the type of this is the same as the type of C.this. (Scala Ref. §6.5)
So, if you call your self-type foo, you could still refer to it as this (unless, of course, you are in an inner template in which case this will refer to the object defined by it – and unless you don’t give the inner template’s self-type the same name) but obviously not the other way round.
Related
Anonymous class definition is
An anonymous class is a synthetic subclass generated by the Scala
compiler from a new expression in which the class or trait name is
followed by curly braces. The curly braces contains the body of the
anonymous subclass, which may be empty. However, if the name following
new refers to a trait or class that contains abstract members, these
must be made concrete inside the curly braces that define the body of
the anonymous subclass.
Refinement type definition is
A type formed by supplying a base type a number of members inside
curly braces. The members in the curly braces refine the types that
are present in the base type. For example, the type of “animal that
eats grass” is Animal { type SuitableFood = Grass }
-- Both definitions are taken from book Programming in Scala Fifth Edition by Martin Odersky and others.
What is the difference? Can you illustrate it with simple examples?
Let's see my code example which compiles:
abstract class A:
type T
// anonymous class
var o1 = new A { type T = String }
// refinement type
var o2: A { type T = String } = null
o1 = o2 // OK
o2 = o1 // OK
It seems to me that refinement type is a handy way to create a new type, which anonymous class does implicitly.
As Dmytro Mitin pointed out in [1] and [2], the main difference is the same as the difference between class and type.
A type restricts the possible values to which a variable can refer, or an expression can produce, at run time. Refinement type is still a type, which may be used instead of defining a new class.
Without using the refinement type in the example, you would have to define a new class.
class AString extends A:
type T = String
A class is a blueprint for objects. Once you define a class, you can create objects from the class blueprint with the keyword new.
Type and class are different (and actually orthogonal) concepts. Types belong to type theory, classes belong to OOP. Classes exist in bytecode, types mostly don't exist in bytecode (if they are not persisted to runtime specially or if they don't correspond to classes obviously).
What is the difference between a class and a type in Scala (and Java)?
What is the difference between Type and Class?
https://typelevel.org/blog/2017/02/13/more-types-than-classes.html
new A { type T = String } is a shorthand for
{
class AImpl extends A {
type T = String
}
new AImpl
}
If you define an anonymous class
val o1 = new A { type T = String }
the type of o1 can be, for example, refined
val o1: A { type T = String } = new A { type T = String }
or even structural
val o1: A { type T = String; def foo(): Unit } = new A {
type T = String
def foo(): Unit = println("foo")
}
or not refined if we statically upcast, just
val o1: A = new A { type T = String }
So defining an anonymous class doesn't mean that the type of variable is a refinement type.
On the other hand, you can consider refined type
type X = A { type T = String }
val o2: A { type T = String } = null
not introducing an anonymous class. The only class in bytecode now is A, there is no AImpl (until you instantiate new ...).
Scala refined types can be compared with refinement types in type theory (or programming languages with dependent types), i.e. (dependent) types endowed with a predicate.
I have something like the following code (I simplified it):
trait A {
val CONST_VALUE = 10
}
class B(someValue: Int, values: Array[Int]) extends A {
//some methods
}
object B {
def apply(someValue: Int) = B(someValue, Array.ofDim[Array[Byte]](someValue).map(block => Array.fill[Byte](A.CONST_VALUE)(0)))
}
Basically, I declared a constant CONST_VALUE in the trait A. I am trying to use it in the companion object B to instantiate the class B. However, I can't access A.CONST_VALUE from the companion object B.(I'm getting a compilation error).
So how could I do this?
You can't do this.
First of all, object B is the companion object to class B, not to trait A. Companions need to have the same name and be defined in the same compilation unit.
Secondly, CONST_VALUE is an instance field of trait A. It is a member of an instance of A, not a member of A.
Thirdly, when you say A.CONST_VALUE you are basically calling the method CONST_VALUE on A. But you can only call methods on objects/values. A is not an object, it is a type, types and values live in different worlds, you cannot mix the two.
And fourth, your CONSTANT_VALUE is misleadingly named: only final vals are constant value definitions, so your CONSTANT_VALUE is not actually a constant value.
Fifth, your apply method calls itself (B() is syntactic sugar for B.apply()), and thus needs a return type annotation.
Sixth, your apply method calls itself with two arguments, but it is defined with only one parameter.
Seventh, you create an Array[Array[Byte]], but it is not clear to me why you want to do that and what you need it for.
That's a whole truckload of problems (especially considering that there are only a handful of lines of code to begin with), which you need to fix one-by-one. Here's one possible partial solution, but it is not clear to me what it is exactly that you are trying to achieve.
trait A
object A {
final val CONST_VALUE = 10
}
class B(someValue: Int, values: Array[Int]) extends A {
//some methods
}
object B {
def apply(someValue: Int): B = new B(
someValue,
Array.ofDim[Array[Byte]](someValue).map(block => Array.fill[Byte](A.CONST_VALUE)(0)))
}
Declare val CONST_VALUE = 10 inside the companion object A instead of trait A. Also corrected the apply method definition in object B
trait A {
}
object A {
final val CONST_VALUE = 10
}
class B(someValue: Int, values: Array[Int]) extends A {
//some methods
}
object B {
def apply(someValue: Int) = new B(someValue, Array.ofDim[Int](someValue).flatMap(block => Array.fill[Int](A.CONST_VALUE)(0)))
}
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 have two questions about nested types in Scala.
Imagine I have this kinda trait;
trait ScanList[E] {
sealed trait Command
case object Recover extends Command
case class Remove(item: E) extends Command
sealed trait Event
case class Removed(item: E) extends Event
}
And now I want to write a generic trait over this like this (the problems are encoded in the pattern matches as comment):
trait ScanListProcessor[E] {
type SL = ScanList[E]
def process(msg: SL#Command) = {
msg match {
case u:SL#Remove => // how can instantiate SL#Removed here?
case SL#Recover => //cannot match on nested objects?
}
}
}
The reason for using a trait is that I can derive new implementations of ScanList. In this trait I also have operations like def shouldProcess(item: E): Boolean. For each implementation of ScanList[E] I would like to write generic behaviour like depicted above.
How can pattern match on nested object in a generic type?
Is it possible to instantiate from a type constructor? For example: SL#Removed? I guess it's the same having a generic parameter and trying to construct a value from that, type classes would solve this?
Nested traits, class, and objects in Scala act like inner classes in Java. Any instance of them that you create is associated with an instance of the parent class/trait that they are created from. So continuing from your example:
val sl1 = new ScanList[Int] {}
val sl2 = new ScanList[Int] {}
val r1 = sl1.Removed(1) // has type sl1.Removed
val r2 = sl2.Removed(2) // has type sl2.Removed
val rs = List(r1, r2) // has type List[ScanList[Int]#Removed]
You can pattern match on them like:
rs match {
case List(sl1.Removed(x), sl2.Removed(y)) => (x, y)
}
Pattern matching requires that you explicitly references the parent instance that the nested instance belongs to. Here, we separately match on sl1.Removed and sl2.Removed.
As for you second question, you cannot create a SL#Removed without having a parent instance available. With one, it is as simple as sl1.Removed(1).
Your ScanListProcessor could be rewritten to take the ScanList it operates on as a value:
class ScanListProcessor[E](val sl: ScanList[E]) {
def process(msg: sl.Command) = {
msg match {
case sl.Remove(x) => sl.Removed(x)
case sl.Recover => ???
}
}
}
But this is awkward, and nested types probably aren't needed here. If all you want to do is group some traits, classes etc. together in a namespace, then put them in a package or object instead of a trait or class. In this case you would need to move the type parameter E down onto Remove and Removed themselves:
object ScanList {
sealed trait Command
case object Recover extends Command
case class Remove[E](item: E) extends Command
sealed trait Event
case class Removed[E](item: E) extends Event
}
In various Scala literature I see some self-type annotations using "this" and others using "self":
trait A { this: B => ... }
trait A { self: B => ... }
Is there any real difference between using "this" or "self"? Does it matter at all what name you use? Is this just as valid?
trait A { foo: B => ... }
All three forms are valid, and have the effect that B is assumed as the type of this in class A.
The first two variants
trait A { self: B => ... }
trait A { foo: B => ... }
introduce self (respectively, foo) as an alias for this in trait A. This is useful for accessing the this reference from an inner class. I.e. you could then use self instead of A.this when accessing the this reference of the trait A from a class nested within it. Example:
class MyFrame extends JFrame { frame =>
getContentPane().add( new JButton( "Hide" ) {
addActionListener( new ActionListener {
def actionPerformed( e: ActionEvent ) {
// this.setVisible( false ) --> shadowed by JButton!
frame.setVisible( false )
}
})
})
}
The third variant,
trait A { this: B => ... }
does not introduce an alias for this; it just sets the self type.
There is a difference in that this always refers to the object defined by the innermost template.
The expression this can appear in the statement part of a template or compound type. It stands for the object being defined by the innermost template or compound type enclosing the reference. If this is a compound type, the type of this is that compound type. If it is a template of a class or object definition with simple name C, the type of this is the same as the type of C.this. (Scala Ref. §6.5)
So, if you call your self-type foo, you could still refer to it as this (unless, of course, you are in an inner template in which case this will refer to the object defined by it – and unless you don’t give the inner template’s self-type the same name) but obviously not the other way round.