matanox
matanox

Reputation: 13706

involved usage of overridden methods, type bounds, and... type erasure

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

Answers (2)

Shadowlands
Shadowlands

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

matanox
matanox

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

Related Questions