You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I needed a new sub-type / tagged type for a value class. It had to be a sub-type because I needed to use it in all the places where the base type could be used but perhaps more importantly I needed all the implicit conversions to be found from its companion object.
The problem with @newsubtype is that it doesn't support value classes. One reason is because the Ops$newtype is a value class which cannot wrap another user-defined value class.
I tried doing something more like what Shapeless does but then I run into a bunch of ClassCastExceptions. I initially reported that in scala-js/scala-js#4778 as I thought it was a Scala.js specific issue but that turns out to be untrue. I found a bunch of related Shapeless issues (see that issue for links).
I started wondering how it was that @newtype avoided these ClassCastExceptions (and as hinted by Miles in some of his comments that Shapeless 3 may change Tagged back to how it was). It seems that the structural type is the key here.
We of course need the type we are extending somewhere in Type for it to be a subtype but it can't be in Base.
This encoding seems to do the trick:
import scala.language.implicitConversions
object Main {
final class KeyAddingStage(private val args: Array[Any]) extends AnyVal
object KeyAddingStage {
implicit def build(stage: KeyAddingStage): String = stage.toString
}
type RenderedProps[Props] = RenderedProps.Type[Props]
object RenderedProps {
type Base = {
type __RenderedProps__newtype
}
trait Tag[Props] extends Any
type Type[Props] <: Base with KeyAddingStage with Tag[Props]
def apply[Props](stage: KeyAddingStage): RenderedProps[Props] = stage.asInstanceOf[RenderedProps[Props]]
}
object Name {
case class Props(name: String)
def component(props: Props): KeyAddingStage = new KeyAddingStage(
Array(
props.asInstanceOf[Any]
)
)
def apply(name: String): RenderedProps[Props] = RenderedProps(component(Props(name)))
}
def main(args: Array[String]): Unit = {
val first: RenderedProps[Name.Props] = Name("Jason")
val firstStage: KeyAddingStage = first
val str: String = first
println(first == firstStage)
val props: Seq[RenderedProps[Name.Props]] = Seq(first)
val propsHead: RenderedProps[Name.Props] = props.head
println(firstStage == propsHead)
}
}
Any thoughts on adding something like this so that we can have @newsubtype support for value classes?
The text was updated successfully, but these errors were encountered:
I needed a new sub-type / tagged type for a value class. It had to be a sub-type because I needed to use it in all the places where the base type could be used but perhaps more importantly I needed all the implicit conversions to be found from its companion object.
The problem with
@newsubtype
is that it doesn't support value classes. One reason is because theOps$newtype
is a value class which cannot wrap another user-defined value class.I tried doing something more like what Shapeless does but then I run into a bunch of
ClassCastException
s. I initially reported that in scala-js/scala-js#4778 as I thought it was a Scala.js specific issue but that turns out to be untrue. I found a bunch of related Shapeless issues (see that issue for links).I started wondering how it was that
@newtype
avoided theseClassCastException
s (and as hinted by Miles in some of his comments that Shapeless 3 may changeTagged
back to how it was). It seems that the structural type is the key here.We of course need the type we are extending somewhere in
Type
for it to be a subtype but it can't be inBase
.This encoding seems to do the trick:
Any thoughts on adding something like this so that we can have
@newsubtype
support for value classes?The text was updated successfully, but these errors were encountered: