1 / 22

Family Polymorphism

Explore class families and the “OnOffGraph” example in C++, comparing traditional polymorphism with family polymorphism. Learn about mutable instances, safe type handling, and the challenges of implementation. Discover how Family Polymorphism increases flexibility and safety in managing polymorphic classes together.

bonniew
Télécharger la présentation

Family Polymorphism

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Family Polymorphism by Erik Ernst

  2. Outline • Class families • The “OnOffGraph” example • Traditional polymorphism • C++ approach • Family polymorphism • Implementation difficulties • Mutable instances • Where to find the pointer • When is it type safe • Comparison with VirtualTypes

  3. Class Families • Express multi-object relations • Flexibility • Safety • Classes are declared and managed in a “family” and they polymorphic together.

  4. Node Edge Families OnOffNode OnOffEdge The OnOffGraph Example • There are edges and nodes in a graph. • I.e. Edge and Node is in a family Graph. • OnOffEdge and OnOffNode are in the family OnOffGraph.

  5. Traditional Polymorphism(The Naïve approach) class Node{ boolean touches(Edge e){… } }class Edge{ Node n1, n2; } class OnOffNode extends Node{ boolean touches(Edge e){ return ((OnOffEdge)e).enabled ? super.touches(e) : false; }}class OnOffEdge extends Edge{ boolean enabled; } void build(Node n, Edge e){ e.n1 = e.n2 = n; if(n.touches(e)) println(“OK”);}

  6. Traditional Polymorphism (cont.) • build(new Node(), new Edge()) • build(new OnOffNode(), new OnOffEdge()) • build(new OnOffNode(), new Edge())// ClassCastException • build(new Node(), new OnOffNode())// “works” • Reuse: Yes; Safety: No

  7. template<class N, class E> struct EdgeF{ N* n1, n2; };template<class N, class E> struct NodeF{ virtual bool touches(E* e); }; struct Edge: public EdgeF<Node, Edge>{};struct Node: public NodeF<Node, Edge>{}; template<class ON, class OE> struct OnOffEdgeF: public EdgeF<ON, OE>{ bool enabled; };template<class ON, class OE> strut OnOffNodeF: public NodeF<ON, OE>{ bool touches(OE* e){ return e->enabled ? NodeF<ON, OE>::touches(e) : false; }}; struct OnOffEdge: public OnOffEdgeF<OnOffNode, OnOffEdge>{};struct OnOffNode: public OnOffNodeF<OnOffNode, OnOffEdge>{}; void build1(Node* n, Edge* e){ e->n1 = e->n2 = n; if(n->touches(e)) cout << “OK\n”;} void build2(OnOffNode* n, OnOffEdge* e){ e->n1 = e->n2 = n; if(n->touches(e)) cout << “OK\n”;} C++ approach

  8. C++ approach (cont.) • build1(new Node, new Edge) • build2(new OnOffNode, new OnOffEdge) • build1(new OnOffNode, new Edge)// type error • build2(new Node, new OnOffEdge)// type error • Safety: Yes; Reuse: No

  9. C++ approach problems • Reusability: using template (but not really “reuse” the function) template<class N, class E> void build(N* n, E* e){ … } • But problems arise

  10. template<class N, class E>struct GraphF{ typedef N Node; typedef E Edge;}; typedef GraphF<Node, Edge> Graph;typedef GraphF<OnOffNode, OnOffEdge> OnOffGraph; template<class G>void build(const G&, typename G::Node* n, typename G::Edge* e){ … } build(Graph(), new Node, new Edge); C++ approach problems (cont.) • Every involved function have to be template functions and the exact type (Node and Edge, or OnOffNode and OnOffEdge) should be known, not any thing like “a subfamily of Graph.”

  11. C++ approach problems (cont.) • A template function may not be a virtual member function • Limits usage on known Node-Edge system • Generic in Java 1.5 doesn’t have such problem

  12. C++ approach problems (cont.) • No coupled containers to store nodes and edges belonging together template<class G>struct NodesAndEdges{ vector<typename G::Node> nodes; vector<typename G::Edge> edges;}

  13. C++ approach problems (cont.) • All usages of nodes and edges are performed in a context where the exact classes are known • May increase the dependency of implementation details

  14. Family polymorphism (# Graph: (# Node:< (# touches:< (# e: ^Edge; b: @boolean enter e[] do (this(Node)=e.n1) or (this(Node)=e.n2) -> b exit b #) exit this(Node)[] #); Edge:< (# n1, n2: ^Node exit this(Edge)[] #) #); OnOffGraph: Graph (# Node::<(# touches::<!(# do (if e.enabled then INNER if) #)#) Edge::<(# enabled: @boolean #) #); build: (# g:< @Graph; n: ^g.Node; e: ^g.Edge enter(n[], e[]) do n -> e.n1[] -> e.n2[]; (if (e->n.touches) then ‘OK’ ->putline if) #);

  15. Family polymorphism (cont.) • g1: @Graph; g2: @OnOffGraph • (g1.Node, g1.Edge) -> build(# g::@g1 #) • (g2.Node, g2.Edge) -> build(# g::@g2 #) • (g2.Node, g1.Edge) -> build(# g::@g1 #)(* type error *) • (g2.Node, g1.Edge) -> build(# g::@g2 #)(* type error *) • Reuse: Yes; Safety: Yes • Class families are associated with instances (g1, g2), not classes (Graph, OnOffGraph)

  16. Family polymorphism (cont.) • Coupled containers: NodesAndEdges:(# g:< @Graph; nodes: @list(# element::g.Node #); edges: @list(# element::g.Edge #)#) myGraph: @LabelledGraph;myNodesAndEdges: @NodesAndEdges(# g::@myGraph #) listBuild:(# ne:< @NodesAndEdges; n: ne.g.Node; e: ^ne.g.Edge do ne.nodes.head -> n[]; ne.edges.head -> e[]; (n, e) -> build(# g::@ne.g #)#) m1: (# x: ^NodesAndEdges enter x[] do listBuild(# ne::@x #) #)m2: (# x: ^NodesAndEdges enter x[] do x[] -> m1 #)

  17. Implementation DifficultiesMutable Instances • Mutable instance “ne” in listBuild will change the type at runtime and destroy the correctness. • Only the types from the immutable references are considered the same in multiple appearances

  18. Implementation DifficultiesWhere Is The Pointer • Circle and Rectangle and subclasses of GraphicalObjects with method draw • Traverse a List whose elements are typed as GraphicalObjects and invoke draw of them. • There may not exist any pointers typed by the actual class to each object in the list in the program state

  19. Implementation DifficultiesWhere Is The Pointer (cont.) • To type the families correctly, the single-object way does not work • Possible approach: use wrapper classes like NodesAndEdges which stores a Graph instance then have a list of these wrappers • Rediscover: instanceof • Restrict usage on known families

  20. Implementation DifficultiesWhen is it type safe • Virtual patterns (virtual types) are attributes of objects, not classes • Virtual patterns have a kind of existential type:x is an object of type T (typed as T)V is a virtual attribute in T x.V has the type T.V i.e. ∃T’V ≤ TV . T’V • y is another instance typed as Ty.V can be ∃T’’V ≤ TV . T’’VT’’V may not equal to T’V

  21. Implementation DifficultiesWhen is it type safe (cont.) • Virtual types can be change into ordinary types by final binding[Tor98] • Immutable reference is equally valid • this is an immutable reference

  22. Comparison with VirtualTypes • [Bru98] • Based on exact references • Virtual types are attributes of classes • [Tor98] • Type system similar • The language in it is a pseudo one • Not emphasized that virtual types are attributes of objects

More Related