We need black box macros for final class definition. For example
create[Card]
which will generate something like
new Card {
def this2Tag[MAVI <: AnyRef](avi: MAVI)(implicit tag: TypeTag[MAVI]): TypeTag[MAVI] =tag
override def meta = this2Tag(this)
}
Or without macros, we can use implicit:
class Form[T](implicit tag: TypeTag[T]) extends DefaultForm {
override def meta: TypeTag = tag
}
new Form[Card] with Card
Unfortunately there is no simple way to guaranty that the end user specify type parameter.
So the code will not work correctly in runtime after correct compilation.
Could you elaborate on what youād like Scala to do more concretely? The link you provide in SO is helpful in understanding what you want to see, but all we can do is guessing, and I imagine most people in the forum wonāt take the time to go and read the long answer in the SO question
Usually, the best way to propose a change is to provide more or less all the information needed for someone to implement the change you want to see, with clear examples of what youāre trying to do, how your code does it, and how youād like it to work.
I think youāre talking about two different things. Your last example is not related to the example that you link in the SO question. Letās tackle the discrepancy first.
sumFunc with no type parameters is inferred to be Nothing and then the implicit search is triggered for whatever type youāre looking for, in this case Holder. If the implicit Holder[Nothing] did not exist in your example, then sumFunc with no type parameter would fail, as shown by the following REPL session:
ā Code scala
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_172).
Type in expressions for evaluation. Or try :help.
scala> class Holder[T]
defined class Holder
scala> def sumFunc[T: Holder]: T = ???
sumFunc: [T](implicit evidence$1: Holder[T])T
scala> sumFunc
<console>:13: error: could not find implicit value for evidence parameter of type Holder[T]
sumFunc
^
When you add implicit def holderNothing: Holder[Nothing] = ??? and try again, sumFunc succeeds because itās inferred to be sumFunc[Nothing] and there exists an implicit Holder[Nothing].
So, coming back to your initial example with Form and TypeTag (which I havenāt fully understood, but Iāll use the example in the SO question as a reference), what you seem to want is to avoid a definition type to be inferred to Nothing. For example, in val person = find("Joe"), person is typed as Nothing because the type in find is not set at the call-site and the return type is the same polymorphic type T, with no further type restrictions. This is the expected behavior of the code.
The Scala way of avoiding Nothing to be inferred is to create your own type class and then restrict the return type the function will return by using implicits at the definition site of find (or sumFunc in your previous case). So long as you donāt define the implicit for Nothing, the code find("Joe") will fail to compile if you implement something like the answer in the SO question.
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_121).
Type in expressions for evaluation. Or try :help.
scala> import scala.reflect.runtime.universe._
class Form[T](implicit tag: TypeTag[T]){
def meta: TypeTag[_] = tag
}
trait SomeView{
def someMethod():Unit = ???
}
//I need that `Form` has meta data about it's view.
new Form[SomeView] with SomeView
new Form with SomeView //It compiles, but it has no sence, it's error
import scala.reflect.runtime.universe._
scala> | | defined class Form
scala> | | defined trait SomeView
scala>
scala> res0: Form[SomeView] with SomeView = $anon$1@10e4ce98
scala>
scala> res1: Form[Nothing] with SomeView = $anon$1@20505460
scala>
So if I want to save user from errors, I need some hack
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_121).
Type in expressions for evaluation. Or try :help.
scala> import scala.annotation.implicitAmbiguous
import scala.reflect.runtime.universe._
class TagHolder[T ](val tag:TypeTag[T] )
@implicitAmbiguous("Set parameter")
implicit def tagHolder1: TagHolder[Nothing] = null
implicit def tagHolder2: TagHolder[Nothing] = null
implicit def tagHolder[T ](implicit tag: TypeTag[T]):TagHolder[T] = new TagHolder(tag)
class Form[T](implicit th: TagHolder[T]){
def meta: TypeTag[_] = th.tag
}
trait SomeView{
def someMethod():Unit = ???
}
import scala.annotation.implicitAmbiguous
scala> import scala.reflect.runtime.universe._
scala> defined class TagHolder
scala> | tagHolder1: TagHolder[Nothing]
scala> tagHolder2: TagHolder[Nothing]
scala> tagHolder: [T](implicit tag: reflect.runtime.universe.TypeTag[T])TagHolder[T]
scala> | | defined class Form
scala> | | defined trait SomeView
scala> new Form[SomeView] with SomeView
res0: Form[SomeView] with SomeView = $anon$1@331fe6d4
scala> new Form with SomeView
<console>:21: error: Set parameter
new Form with SomeView
^
scala>
import scala.reflect.runtime.universe._
class Form[T](implicit tag: TypeTag[T]){
def meta: TypeTag[_] = tag
}
trait SomeView{
def someMethod():Unit = ???
}
new Form with SomeView //It compiles, but it has no sence, it's error
...
scala> res1: Form[Nothing] with SomeView = $anon$1@20505460
scala>
āāā @implicitAmbiguous(āSet parameterā)
implicit def tagHolder1: TagHolder[Nothing] = null
implicit def tagHolder2: TagHolder[Nothing] = null
āāā
I donāt think it is a good solution for disable Nothing.
Moreover I think there are many other cases, for example with orm Itās quite common to write something like
val id = 10L
val person = session.load[Person](id)
And type define table. If type is not defined it is error.
it would be very good if IDE can assist that case.(insert āā automaticly [Just a litle dream :)] )
We could debate whether if Scala has no information how to infer a type argument, it should arbitrarily pick Nothing. Iāve had runtime errors when I assumed Scala could infer the right type from the context when in fact it inferred Nothing. I think thereās a reasonable case to be made, that if Scala can infer nothing about a type argument, it should not infer Nothing. Instead it would be an error to omit it.
That is exactly what the SO answer proposes too, and what I claimed to be the solution Thanks for writing down the code snippet in the thread, Iām sure it will be useful for others in the future.
Sometimes it makes sense to omit a type parameter, because it is not needed, like
**Welcome to Scala 2.12.4 (OpenJDK 64-Bit Server VM, Java 1.8.0_171).
Type in expressions for evaluation. Or try :help.
^
def m[T](opt: Option[T]): String = opt.map(x => "I got some " + x.toString).getOrElse(āI got nothing.ā)
m: [T](opt: Option[T])String
m(None)
res1: String = I got nothing.**
In this case, we donāt want an error and Nothing makes perfect sense. Should we instead have a type Unknown? Would Unknown ever behave differently from Nothing?
In that case Scala is inferring Nothing because it has information that suggests Nothing, namely that None extends Option[Nothing]. Thatās fine by me. What Iām arguing is that Scala should kick the habit of making inferences when it has zero information at all about what to infer. At that point Nothing is not even a reasonable guess, itās simply picking Nothing because it doesnāt want to give up.