Is there an (dis)advantage (for example performance-wise) for defining classes auxiliary to a trait in its companion object over defining them as inner classes? For example:
object Foo {
final class Bar[A, B](val x: A, val y: B)
}
trait Foo[A, B] {
def foo: Foo.Bar[A, B]
}
vs.
trait Foo[A, B] {
final class Bar(val x: A, val y: B)
def foo: Bar
}
I tend to use the first variant—because it does not require access to any member of Foo—but since the type parameters become redundant, I'm thinking about switching to the second variant. Class Bar is only used internally, so could get a protected modifier.
I reckon the internal class with have an invisible Foo.this member somewhere, but then my understanding is that Foo.Bar is also not purely static as in Java but probably has some pointer to Foo$.this, too.
Related
I wonder what is the reasoning behind the following behaviour?
# trait Bar
defined trait Bar
# trait Foo { self: Bar => }
defined trait Foo
# def x: Foo = ???
defined function x
# val y: Bar = x
cmd3.sc:1: type mismatch;
found : ammonite.$sess.cmd1.Foo
required: ammonite.$sess.cmd0.Bar
val y: Bar = x
^
Compilation Failed
AFAIU, Foo requires each of its subtypes to be a subtype of Bar so why instance of Foo is not a proper instance of Bar?
#Edit
Just to make the question clearer: I wonder why it works like that. Some possible answers are:
There is feature X that would not be possible with subtyping relation between those.
It's not true that the subtyping relation occurs (e.g. exists such instance of type Foo which is not the instance of type Bar in runtime)
Both scenarios (with and without subtyping relation) are valid and so the compiler team had to choose one of them. If so, was there a reason to make such a decision or it was a random choice?
It seems that at least 1) is somewhat true (hiding subtyping as implementation detail).
Because a selftype is an implementation detail of the Foo trait. You may want to implement Foo's methods in terms of methods that you inherit from Bar, but not expose that fact to the users of your API.
Back in 12-Mar-2006 Scala 2.0 introduced new keyword
requires
which was used to represent self types
class C requires T extends B { ... }
requires keyword was eventually deprecated on 27-Jul-2007 in Scala 2.6.0 in favour of the current self type syntax
The requires clause has been deprecated; use { self: T =>; ... }
instead
however it serves as a good indicator of the design intention of the self type which was to model relationship of "Bar requires Foo" as opposed to "Bar is Foo", as per Daniel
Now, as to what is the difference between a self type and extending a
trait, that is simple. If you say B extends A, then B is an A. When
you use self-types, B requires an A.
For example, programer requires coffee, but that does not necessarily mean programer is coffee (although I would not be surprised if few lost souls managed the transition).
Furthermore, bug issue Can't access public members despite bounded 'this' #9718, which is similar to OP, was closed with #retronym (a compiler contributor) stating
The current behaviour is as specified and actually a feature: the
self type is an implementation detail of Bar that should not be
visible to clients.
AFAIU, Foo requires each of its subtypes to be a subtype of Bar
No it doesn't.
def test[T <: Foo]: Unit = {
implicitly[T <:< Bar] // doesn't compile
}
I defined a subtype of Foo, namely T, which is not a subtype of Bar.
This is true for subclasses.
class Impl extends Foo with Bar
If a class extends Foo it must extend Bar too.
Types and classes are different. Subtypes and subclasses are different. Subtyping and inheritance are different.
In
trait Foo { self: Bar => }
Foo is not a subtype of Bar. So you can't assign value of type Foo to variable of type Bar
def x: Foo = ???
val y: Bar = x // doesn't compile
If you want to make Foo a subtype of Bar you should use inheritance
trait Foo extends Bar
def x: Foo = ???
val y: Bar = x // compiles
or subtyping
type Foo <: Bar
def x: Foo = ???
val y: Bar = x // compiles
For example with self-types you can define cyclic dependencies:
trait Bar { self: Foo => }
trait Foo { self: Bar => }
class Impl extends Foo with Bar
If trait A { self: B => } implied that A <: B then we would have in such case that Bar <: Foo and Foo <: Bar, so Bar =:= Foo but it's not true, types of those traits are different.
trait A { self: B => } could mean that A <: B (and in such case either we wouldn't have cyclic dependencies or such traits would have equal types) but there is no necessity in that: if you need A <: B you can just declare A extends B while trait A { self: B => } has a different meaning: all subclasses (not subtypes) of A are subtypes of B.
Or you can limit implementation
trait Foo { self: Impl => }
class Impl extends Foo
(Impl can be the only implementation of trait Foo like making Foo sealed with the only inheritor) but there is no need to make types of Foo and Impl the same.
Let's consider also the following example
trait NatHelper {
//some helper methods
}
sealed trait Nat { self: NatHelper =>
type Add[M <: Nat] <: Nat
}
object Zero extends Nat with NatHelper {
override type Add[M <: Nat] = M
}
class Succ[N <: Nat] extends Nat with NatHelper {
override type Add[M <: Nat] = Succ[N#Add[M]]
}
Notice that the abstract type Nat#Add[M] is a subtype of Nat but there is no need to make it a subtype of NatHelper.
Types are not necessarily connected with runtime stuff. Types can have independent meaning. For example they can be used for type-level programming when you formulate your business logic in terms of types.
Also there are so called tagged types (or phantom types) when you attach some information to a type
val x: Int with Foo = 1.asInstanceOf[Int with Foo]
Here we attached "information" Foo to number 1. It's the same runtime number 1 but at compile time it's enriched with "information" Foo. Then x.isInstanceOf[Bar] gives false. I'm not sure you'll accept this example since we use asInstanceOf but the thing is that you can use some library function
val x: Int with Foo = 1.attach[Foo]
and you will not know that it uses asInstanceOf under the hood (as often happens), you will just trust its signature that it returns Int with Foo.
Let's say I have a coproduct (a sealed trait) such as
sealed trait Traity
case object Foo extends Traity
case class Bar() extends Traity
case class Baz() extends Traity
Using shapeless, I can apply polymorphic functions to specific instances but what I'd like to do is to apply a zero-parameter (no-instance) polymorphic function to all the products (i.e. case classes and case objects). I have no idea what the syntax would look like, but something conceptually like:
object mypoly extends Poly1 {
implicit def traity[T <: Traity] = when[T]( getClass[T].toString )
}
iterate[Traity](mypoly) // gives List("Foo", "Bar", "Baz")
would suit my purposes.
For the example use case in your question, this is actually very straightforward:
import shapeless._
class NameHelper[A] {
def apply[C <: Coproduct, K <: HList]()(implicit
gen: LabelledGeneric.Aux[A, C],
keys: ops.union.Keys.Aux[C, K],
toSet: ops.hlist.ToTraversable.Aux[K, Set, Symbol]
): Set[String] = toSet(keys()).map(_.name)
}
def names[A] = new NameHelper[A]
And then:
scala> names[Traity]()
res0: Set[String] = Set(Bar, Baz, Foo)
(I'm using a Set since the order you're getting is just alphabetical—it's not currently possible to enumerate the constructors in declaration order, although I'd personally prefer that.)
If you'd like a more generic answer, an adaptation of the code in the question I linked above shouldn't be too bad—I'd be happy to add it here later.
I have (for lack of a better term) a factory method that encapsulates constructing an object:
def createMyObject = new SomeClass(a, b, c, d)
Now, depending on the context, I will need to mix in one or more traits into SomeClass:
new SomeClass with Mixin1
or
new SomeClass with Mixin2 with Mixin3
Instead of creating multiple separate factory methods for each "type" of instantiation, how can I pass in the traits to be mixed in so that it can be done with a single method? Or perhaps there is a good pattern for this that is structured differently?
I'd like to maintain the encapsulation so I'd rather not have each consumer just create the class on its own.
If you need only mixins without method overriding, you can just use type classes:
trait Marker
class C[+T <: Marker] { def b = 1 }
trait Marker1 extends Marker
implicit class I1[T <: Marker1](c: C[T]) {def a = 6 + c.b}
trait Marker2 extends Marker
implicit class I2[T <: Marker2](c: C[T]) {def a = 5 + c.b}
trait Marker3 extends Marker
implicit class I3[T <: Marker3](c: C[T]) {def k = 100}
trait Marker4 extends Marker3
implicit class I4[T <: Marker4](c: C[T]) {def z = c.k + 100} //marker3's `k` is visible here
scala> def create[T <: Marker] = new C[T]
create: [T <: Marker]=> C[T]
scala> val o = create[Marker1 with Marker3]
o: C[Marker1 with Marker3] = C#51607207
scala> o.a
res56: Int = 7
scala> o.k
res57: Int = 100
scala> create[Marker4].z
res85: Int = 200
But it won't work for create[Marker1 with Marker2].a (ambiguous implicits), so no linearization here. But if you want to just mix-in some methods (like in javascript's prototypes) and maybe inject something - seems to be fine. You can also combine it with traditional linearized mix-in by adding some traits to C, I1, I2, etc.
You can instantiate the class differently depending on the context.
def createMyObject =
if (context.foo)
new SomeClass
else
new SomeClass with Mixin1
However, if the consumers are the ones that know the traits that are supposed to be mixed in, then why wouldn't you just instantiate things there?
Is there a way for me to define the same implicit ordering for two different classes?
I tried to do something along the following lines but it doesn't detect the ordering.
abstract class Common
case class A extends Common
case class B extends Common
implicit val KeyOrdering = new Ordering[Common] {
override def compare(x: Common, y: Common): Int = {
x.toString.compareTo(y.toString)
}
}
As noted by #ntn, the inferred type of your list - the least upper bound of its two elements - is Product with Serializable with Common. As scala.Ordering is not contravariant on its type parameter, implicit resolution fails because it does not hold that Ordering[Common] <: Ordering[Product with Serializable with Common].
You can work around this by writing the implicit ordering so that it always has the exact type of the implicit parameter under consideration:
abstract class Common
case class A() extends Common
case class B() extends Common
object Common {
implicit def ordering[A <: Common]: Ordering[A] = new Ordering[A] {
override def compare(x: A, y: A): Int = {
x.toString.compareTo(y.toString)
}
}
}
Or for concision:
object Common {
implicit def ordering[A <: Common]: Ordering[A] = Ordering.by(_.toString)
}
If you remove the case class for A and B (or even only for one of them), then it works.
For List(A(), B()).sorted, it fails to find an Ordering for Product with Serializable with C, as the base class for A and B is Product with C (due to A and B being both case classes).
If you are creating a list with elements of two different base types, I assume you want a list of type List[C], in which you can declare the elements before using them (or get them from some function which returns type C.
val a: C = A()
val b: C = B()
List(a,b).sorted
I'd like to do something like this:
case class D[X <: A](arg1 : X, arg2: Int) extends X {
}
D is kind of a decorator class for arg1, and I'd like to apply it to several different kinds of things that are subclasses of A.
However I get this error:
scala> case class D[X <: A](arg1 : X, arg2: Int) extends X { override val name = "D"; }
:6: error: class type required but X found
If not, is there a more scalaish way to do this kind of thing?
The class that you extend has to be known at compile time and a type parameter is generally not. Therefore, it's not possible to do this.
However, if you're trying to extend X to benefit from the implementations of methods defined in an interface trait A, then you can mix-in X when instantiating the class.
new D with X
If you'd like to preserve the 'case class' features of D, then using D as a proxy which forwards calls to methods defined in A to the parameter arg1 of type X is one solution.
trait A {
def foo
}
case class D[X <: A](arg1: X) extends A {
def forw = arg1
def foo = forw.foo
}