Family Polymorphism 590P Seminar February 16, 2005.

27
Family Polymorphism 590P Seminar February 16, 2005

Transcript of Family Polymorphism 590P Seminar February 16, 2005.

Page 1: Family Polymorphism 590P Seminar February 16, 2005.

Family Polymorphism

590P Seminar

February 16, 2005

Page 2: Family Polymorphism 590P Seminar February 16, 2005.

Traditional polymorphism Let x refer to an object of class C {C1,C2,

…,Cn}, where each Ci provides (or inherits) a method m()

Call site x.m() provides safety: Type checking can ensure that x has an m(). Late-binding ensures correct m() invoked.

Also provides reuse: x can refer to any Ci

Page 3: Family Polymorphism 590P Seminar February 16, 2005.

What is family polymorphism? A family describes a set of related classes. Given a set of families providing a common

interface: {{A1,B1,C1},…,{An,Bn,Cn}} If m() is a method provided by all A’s and

taking an argument of class B, we want reuse: x.m(y) works for any Ai and Bi

Also want safety: Ai and Bi must be from the same family

Page 4: Family Polymorphism 590P Seminar February 16, 2005.

Motivation Traditional OOP allows variability at the level

of a single class. Paper argues that modern software

engineering requires support for variability on a larger scale.

Argue that popularity of aspect-oriented programming demonstrates need for multi-class variability.

Examples??

Page 5: Family Polymorphism 590P Seminar February 16, 2005.

Example: Graphs Two mutually recursive classes Edge

and Node. An Edge has two Nodes. A Node has a method touches(Edge e) that returns true if the edge e touches the node.

Page 6: Family Polymorphism 590P Seminar February 16, 2005.

Extending Graph An OnOffGraph:

OnOffEdge has an extra field enabled OnOffNode.touches(e) only returns

true if e is enabled. Can extend in other ways as well:

Colored graphs Labelled graphs

Page 7: Family Polymorphism 590P Seminar February 16, 2005.

Safety and Reusability Reuse:

Want to write methods that can work with either Edges and Nodes, or with OnOffEdges and OnOffNodes.

Safety: The methods should not allow mixing–e.g.,

attaching an OnOffEdge to a Node. Exisiting approaches can provide reuse or

safety, but not both.

Page 8: Family Polymorphism 590P Seminar February 16, 2005.

Reuse via subtyping

class Node { boolean touches(Edge e) { return (this==e.n1) || (this==e.n2); }}

class Edge { Node n1, n2;}

Page 9: Family Polymorphism 590P Seminar February 16, 2005.

Reuse via subtyping

class OnOffNode extends Node { boolean touches(Edge e) { return ((OnOffEdge)e).enabled? super.touches(e) : false; }}

class OnOffEdge extends Edge { boolean enabled; OnOffEdge() { this.enabled=false; }}

Page 10: Family Polymorphism 590P Seminar February 16, 2005.

Reuse via subtypingpublic class Main { static void build(Node n,Edge e,boolean b){ e.n1=e.n2=n; if (b == n.touches(e)) System.out.println(“OK”); } public static void main(String[] args) { build(new Node(), new Edge(), true); build(new OnOffNode(), new OnOffEdge(), false); }}

Page 11: Family Polymorphism 590P Seminar February 16, 2005.

Why is this unsafe?public class Main { static void build(Node n,Edge e,boolean b){ e.n1=e.n2=n; if (b == n.touches(e)) System.out.println(“OK”); } public static void main(String[] args) { build(new Node(), new Edge(), true); build(new OnOffNode(), new OnOffEdge(), false); build(new OnOffNode(), new Edge(), true); }}

Page 12: Family Polymorphism 590P Seminar February 16, 2005.

Runtime Error!

public static void main(String[] args) { build(new Node(), new Edge(), true); build(new OnOffNode(), new OnOffEdge(), false); build(new OnOffNode(), new Edge(), true); }

class OnOffNode extends Node { boolean touches(Edge e) { return ((OnOffEdge)e).enabled? ...

Page 13: Family Polymorphism 590P Seminar February 16, 2005.

Another unsafe call

This “works” (i.e., no errors, prints OK). But not the intended semantics.

Nodes should be used with Edges, not OnOffEdges.

Node::touches() ignores enabled field

build(new Node(), new OnOffEdge(), true);

Page 14: Family Polymorphism 590P Seminar February 16, 2005.

Try again, with templates

template <class N,class E> struct NodeF;template <class N,class E> struct EdgeF { N *n1,*n2; };template <class N,class E> struct NodeF { virtual bool touches(E* e) { return (this==e->n1) || (this==e->n2); }

struct Edge;struct Node: public NodeF<Node,Edge> {};struct Edge: public EdgeF<Node,Edge> {};

Page 15: Family Polymorphism 590P Seminar February 16, 2005.

On-off graphs

template <class ON,class OE>struct OnOffEdgeF: public EdgeF<ON,OE> { bool enabled; OnOffEdgeF(): enabled(false) {} };template <class ON,class OE>struct OnOffNodeF: public NodeF<ON,OE> { bool touches(OE* e) { return e->enabled ? NodeF<ON,OE>::touches(e) : false; }};

Page 16: Family Polymorphism 590P Seminar February 16, 2005.

On-off graphs, cont…

struct OnOffEdge;struct OnOffNode : public OnOffNodeF<OnOffNode,OnOffEdge> {};struct OnOffEdge : public OnOffEdgeF<OnOffNode,OnOffEdge> {};

Page 17: Family Polymorphism 590P Seminar February 16, 2005.

But no reuse …

void build1(Node* n, Edge* e, bool b) { e->n1=e->n2=n; if (b == n->touches(e)) cout << “OK\n”;}

void build2(OnOffNode *n,OnOffEdge *e,bool b){ e->n1=e->n2=n; if (b == n->touches(e)) cout << “OK\n”;}

OnOffNode not a subtype of Node

Page 18: Family Polymorphism 590P Seminar February 16, 2005.

A templated build()? Could get reuse by templating the

arguments to build. Problems with this approach:

Types must be known statically at call site. When we pass a node to a template

function, every function it passes through in the call chain must be templated.

Can’t create data structures containing nodes and edges belonging together.

Page 19: Family Polymorphism 590P Seminar February 16, 2005.

Reuse and Safety via Virtual Types Virtual types allow types to be attributes

of objects. Thus, we can make an object that acts

as a “repository of types”. These “repositories” can store our

families. We’ll show how this works with gbeta -

beta with support for families.

Page 20: Family Polymorphism 590P Seminar February 16, 2005.

Graphs in gbetaGraph: (# 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)[] #) #);

Page 21: Family Polymorphism 590P Seminar February 16, 2005.

On-off graphs in gbeta

OnOffGraph: Graph (# Node::< (# touches::<!(# do (if e.enabled then INNER if) #) #) Edge::< (# enabled: @boolean #)#);

Page 22: Family Polymorphism 590P Seminar February 16, 2005.

build() in gbeta

build: (# g:<@Graph; n:^g.Node; e:^g.Edge; b:@boolean enter (n[],e[],b) do n->e.n1[]->e.n2[]; (if (e->n.touches)=b then ‘OK’->putline if)#);g1:@Graph; g2:@OnOffGraph

Page 23: Family Polymorphism 590P Seminar February 16, 2005.

build() in gbeta

build: (# g:<@Graph; n:^g.Node; e:^g.Edge; b:@boolean enter (n[],e[],b) do n->e.n1[]->e.n2[]; (if (e->n.touches)=b then ‘OK’->putline if)#);g1:@Graph; g2:@OnOffGraph

(g1.Node, g1.Edge, true) -> build(#g::@g1#);

Page 24: Family Polymorphism 590P Seminar February 16, 2005.

build() in gbeta

build: (# g:<@Graph; n:^g.Node; e:^g.Edge; b:@boolean enter (n[],e[],b) do n->e.n1[]->e.n2[]; (if (e->n.touches)=b then ‘OK’->putline if)#);g1:@Graph; g2:@OnOffGraph

(g2.Node, g2.Edge, false) -> build(#g::@g2#);

Page 25: Family Polymorphism 590P Seminar February 16, 2005.

build() in gbeta

build: (# g:<@Graph; n:^g.Node; e:^g.Edge; b:@boolean enter (n[],e[],b) do n->e.n1[]->e.n2[]; (if (e->n.touches)=b then ‘OK’->putline if)#);g1:@Graph; g2:@OnOffGraph

(g2.Node, g1.Edge, false) -> build(#g::@g2#);

Page 26: Family Polymorphism 590P Seminar February 16, 2005.

build() in gbeta

build: (# g:<@Graph; n:^g.Node; e:^g.Edge; b:@boolean enter (n[],e[],b) do n->e.n1[]->e.n2[]; (if (e->n.touches)=b then ‘OK’->putline if)#);g1:@Graph; g2:@OnOffGraph

(g2.Node, g1.Edge, false) -> build(#g::@g2#);

TYPE ERROR! (because g1 ≠ g2)

Page 27: Family Polymorphism 590P Seminar February 16, 2005.

Family-polymorphic data structures

NodesAndEdges: (# g:< @Graph; nodes: @list(# element::g.Node #); edges: @list(# element::g.Edge #) #)

myGraph: @LabelledGraph;myNodesAndEdges: @NodesAndEdges(#g::@myGraph#)