Reputation: 13706
This is really an involved scenario. Vertices and edges are added to a graph. A convenience method for adding a variable amount of them has been desired. Any way I try to make the latter api requirement happen I fail over type erasure, or a compiler failure to resolve which overridden method needs to be called. Here's the code intent expressed through one failed variation:
/*
* API definition
*/
abstract class AbstractGraph[ID, Vertex <: AbstractVertex[ID], Edge <: AbstractEdge[ID]] {
def += (vertex: Vertex): AbstractGraph[ID, Vertex, Edge]
def += (edge: Edge): AbstractGraph[ID, Vertex, Edge]
def ++=(inputs: Addable*): AbstractGraph[ID, Vertex, Edge] = {
inputs.foreach(i => i match {
case v : AbstractVertex[ID] => this += v
case e : AbstractEdge[ID] => this += e
})
this
}
}
abstract trait Addable
/*
* trait to be mixed in by user code for making their nodes graph friendly
*/
abstract trait AbstractVertex[ID] extends Addable {
val id: ID
}
/*
* trait to be mixed in by user code for making their edges graph friendly
*/
abstract trait AbstractEdge[ID] extends Addable {
val id1: ID
val id2: ID
}
This intent demonstrating variation above, fails with the following:
overloaded method value += with alternatives:
(edge: Edge)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge] <and>
(vertex: Vertex)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge]
cannot be applied to (org.canve.simpleGraph.AbstractVertex[ID])
case v : AbstractVertex[ID] => this += v
^
overloaded method value += with alternatives:
(edge: Edge)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge] <and> (vertex: Vertex)org.canve.simpleGraph.AbstractGraph[ID,Vertex,Edge]
cannot be applied to (org.canve.simpleGraph.AbstractEdge[ID])
case e : AbstractEdge[ID] => this += e
^
Believe me this has been my most elegant attempt... even though it was silly to assume the compiler would infer the appropriate overloaded +=
method from the type bound of its signature's argument type. Practically every other variation I try hits a type erasure wall in some place.
Can you suggest a way to implement the ++=
method after all?
Oddly enough a similarly titled question also came from the realm of graphs ;(
Call me obsessive but not being able to materialize this api is really disappointing so I'd appreciate your help and insight. Of course I could split ++= to a vertices only method and an edges only method, but that alone will... type erasure fail. I could go with different names as well and that might lead the way to fallback from this clean api design - but that excludes providing an elegant api to my library.
Upvotes: 1
Views: 60
Reputation: 15074
I think I can get past the type erasure problem I refer to in my comment using implicit ClassTags:
// Add implicit ClassTag references to AbstractGraph types:
abstract class AbstractGraph[ID, Vertex <: AbstractVertex[ID] : ClassTag, Edge <: AbstractEdge[ID] : ClassTag] {
def += (vertex: Vertex): AbstractGraph[ID, Vertex, Edge]
def += (edge: Edge): AbstractGraph[ID, Vertex, Edge]
def ++= (inputs: Addable*): AbstractGraph[ID, Vertex, Edge] = {
inputs.foreach(i => i match {
case v : Vertex => this += v
case e : Edge => this += e
})
this
}
}
// ... rest as before
Upvotes: 2
Reputation: 13706
I seem to have solved it on top my posted code, by using coercion as follows, but will check all the above comments for other simplifications and possibilities.
case v : AbstractVertex[ID] => += (v.asInstanceOf[Vertex])
case e : AbstractEdge[ID] => += (e.asInstanceOf[Edge])
Comments about this kind of solution are of course most welcome.
Upvotes: 0