Suppose I have a case class below
case class SomeCaseClass[M] private (
value: String
)
and in another file, I have the following trait and object.
trait SomeTrait[A] {
def get(oldId: String): A
:
}
object SomeObject {
private[this] def init[A](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): A = id(oldId)
:
}
val aaa: SomeTrait[String] = init[String]()
val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()
}
How should I modify the code so that restrict the init method only to being used with SomeCaseClass[_] type and not with any types like String as above?
Ideally with some modification to the code, the line val aaa: SomeTrait[String] = init[String]()
should cause compilation error.
The Java language supports five distinct access levels for methods: private, private protected, protected, public, and, if left unspecified, "friendly".
Create a static factory method that keeps track of the instances created. With a private constructor, the users have to use the factory method, which can then throw the exception if more than 5 objects have already been created. One could do the same with an ordinary constructor and some static instance counter.
JButton stopCaptureButton = new JButton("Stop"); panel. add(stopCaptureButton); stopCaptureButton. setBounds(875, 350, 80, 30); stopCaptureButton. addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e){ EspduReceiver.
This is what I came up with:
case class SomeCaseClass[M] private (
value: String
)
trait SomeTrait[A] {
def get(oldId: String): A
}
private[this] def init[A <: SomeCaseClass[_]](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): A = ???
}
val aaa: SomeTrait[String] = init[String]() // Will fail
val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()
It fails with
ScalaFiddle.scala:16: error: type arguments [String] do not conform to method init's type parameter bounds [A <: ScalaFiddle.this.SomeCaseClass[_$1] forSome { type _$1 }]
You can check this scalafiddle.
I do not know if this is the best approach, but init[A <: SomeCaseClass[_]]
is adding a type bound to A
, and forcing A
to be a Subclass of SomeCaseClass
. I would love to know if there is a better way though.
You can force a type parameter to be equal to some type B
by using an implicit parameter:
def foo[A](implicit e: A =:= B): …
Also see this question.
To add some more value to this answer.
Following code shows how to use the implicit parameter e: A =:= String
to convert an A
to a String
.
def bar(b: String): Unit = println(b)
def foo[A](a: A)(implicit e: A =:= String): Unit = {
bar(e(a))
}
foo("hi") //compiles
foo(5) //error: Cannot prove that scala.this.Int =:= String.
This problem is much simpler: Make the method parametric only in the parameter A
of SomeCaseClass[A]
, instead of using the whole type SomeCaseClass[A]
as a type parameter:
private[this] def init[A](): SomeTrait[SomeCaseClass[A]] = new
SomeTrait[SomeCaseClass[A]] {
def get(oldId: String): SomeCaseClass[A] = ???
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With