-
Notifications
You must be signed in to change notification settings - Fork 2
class PG[val t: RDF](node: t.Node, gr: t.Graph)? #133
Comments
class PG[val t: RDF](node: t.Node, gr: t.Graph)
class PG[val t: RDF](node: t.Node, gr: t.Graph)
class PG[val t: RDF](node: t.Node, gr: t.Graph)
You can work around that by adding a type parameter to PointedGraph: class PointedGraph[T <: RDF & Singleton](using val rdf: T)(g: rdf.Graph) {
def foo(): PointedGraph[rdf.type] =
new PointedGraph()(g)
} |
Also you can workaround some of the weirdness with having to add empty parameter lists to constructor calls by adding an apply method in the companion: object PointedGraph {
// Allows writing `PointedGraph(g)` instead of `new PointedGraph()(g)`
def apply[T <: RDF & Singleton](using val rdf: T)(g: rdf.Graph): PointedGraph[T] =
new PointedGraph()(g)
} |
I've reopened scala/scala3#2576 to discuss this issue further. |
Henry, you seem to have similar issue than me in my project Lucre, similar use case and structure indeed, I'm happy to see I'm not alone here. I will keep following to see how you manage to work around the removal of type projections. |
In order to better test my port of banana-rdf I opened a small git repo where I can play with small parts of the translation called banana-play. I have gotten to a good start there. PointedGraph is somewhat more complicated than what we have now. But things get very tricky when one inherits traits with path dependent types. See the need for I discovered that feature request 14 describes quite well the background to the problem. |
How did you solve your problem with Lucre @Sciss ? (I see you moved to Scala3) |
I swapped the position of the outer type, Before: trait Sys[S <: Sys[S]] { // "dominant type"
type Tx <: Txn[S]
type Vr[A] <: Var[S#Tx, A]
type Id <: Ident[S#Tx]
}
trait Txn[S <: Sys[S]] {
def newId(): S#Id
def newVar[A](id: S#Id, init: A): S#Var[A]
}
trait Ident[Tx]
trait Use[S <: Sys[S]] {
def foo()(implicit tx: S#Tx): Any
} after trait Sys
trait Txn[T <: Txn[T]] { // "dominant type"
type Id <: Ident[T]
def newId(): Id
}
trait Ident[T <: Txn[T]] {
def newVar[A](init: A)(implicit tx: T): Var[T, A]
/** Ensures that the identifier is actually valid in the current transaction. */
def ! (implicit tx: T): tx.Id
}
trait Use[T <: Txn[T]] {
def foo()(implicit tx: T): Any
} In the end this looks a bit simpler on the use site, the ubiquitous class IdImpl extends Ident[Plain] {
def !(implicit tx: Plain): Id = this
} |
@Sciss thanks. I will study that. I put up a thread here to help collect ideas on how to deal with this. There are some good ones that have popped up in the last three days. see dotty discussions 12527 |
Porting banana-rdf to Dotty I stumbled across the removal of type projections which we use a lot and I think wisely.
We have an RDF trait which specifies all the main types declared by the W3C specs.
This allowed us to abstract the various Java (Jena from HP/Apache and RDF4J from IBM) and Javascript implementations by defining functions between the types and mapping those methods for each implementation in an
RDFOps[Rdf]
. This allows one to write libraries in an implementation agnostic way by implicitly importing anops
. One can then write code once and change implementation with one line.We could thus create classes like the following:
With the removal of projections in dotty I tried this instead:
which is quite close. The implicit has to come first to be used to select the types in the arguments. Apart from not being usable in case classes it also forces the following usage
Note the extra parenthesis that can't be dropped even using a companion object's
apply
method.So this made me think that something along the lines of the following could be done:
This makes sense since the role of
rdf
is to give us access to the dependent types and I could then imagine that type inferencing could allow one to writeval pg = PointedGraph(p,g)
giving us the same ease of use as before.There is perhaps another reason to think of doing this, which I came across attempting to rewrite the library. I translated the PointedGraphs class to:
But then this fails in a method that returns a PointedGraph, because the dependent type is no longer explicitly tracked. I tried fixing it by writing the following in my IDE
Doing that lead me to discover discover the very interesting Dependent Argument Types PR. (ie. it's an intuitive thing to do).
Following on the proposal here, perhaps the following may be more intuitive:
This is not a feature request, rather a suggestion inquiry, as I don't yet feel
I have a complete grasp of the whole of dotty to be sure I have not missed
some important feature.
The text was updated successfully, but these errors were encountered: