Contributed by Chris Rathman
-module(rectangle). -author('ChrisRathman'). -export([new/4,slots/4,dispatch/1]). % declare record to hold the slots for the class -record( rectangle, { x, y, width, height }). % populate the slots of the object record slots(X, Y, Width, Height) -> #rectangle { x = X, y = Y, width = Width, height = Height}. % create a process for the rectangle instance new(X, Y, Width, Height) -> This = slots(X, Y, Width, Height), spawn(rectangle, dispatch, [This]). % dispatch the messages for the process as they are received dispatch(This) -> receive {Pid, getx} -> Pid!{retval, getx(This)}, dispatch(This); {Pid, gety} -> Pid!{retval, gety(This)}, dispatch(This); {setx, X} -> dispatch(setx(This, X)); {sety, Y} -> dispatch(sety(This, Y)); {moveto, X, Y} -> dispatch(moveto(This, X, Y)); {rmoveto, X, Y} -> dispatch(rmoveto(This, X, Y)); {Pid, getwidth} -> Pid!{retval, getwidth(This)}, dispatch(This); {Pid, getheight} -> Pid!{retval, getheight(This)}, dispatch(This); {setwidth, Width} -> dispatch(setwidth(This, Width)); {setheight, Height} -> dispatch(setheight(This, Height)); {Pid, draw} -> draw(This), Pid!{retval, true}, dispatch(This); dispose -> true end. % get the x & y coordinates for the object getx(This) -> This#rectangle.x. gety(This) -> This#rectangle.y. % set the x & y coordinates for the object setx(This, X) -> This#rectangle{x = X}. sety(This, Y) -> This#rectangle{y = Y}. % move the x & y position of the object moveto(This, X, Y) -> setx(sety(This, Y), X). rmoveto(This, DeltaX, DeltaY) -> moveto(This, getx(This) + DeltaX, gety(This) + DeltaY). % get the width & height of the object getwidth(This) -> This#rectangle.width. getheight(This) -> This#rectangle.height. % set the width and height of the object setwidth(This, Width) -> This#rectangle{width = Width}. setheight(This, Height) -> This#rectangle{height = Height}. % draw the rectangle draw(This) -> io:format('Drawing a Rectangle at:('), io:write(getx(This)), io:format(','), io:write(gety(This)), io:format('), width '), io:write(getwidth(This)), io:format(', height '), io:write(getheight(This)), io:format("~n"). |
-module(circle). -author('ChrisRathman'). -export([new/3,slots/3,dispatch/1]). % declare record to hold the slots for the class -record( circle, { super, x, y, radius }). % populate the slots of the object record slots(X, Y, Radius) -> #circle { x = X, y = Y, radius = Radius}. % create a process for the circle instance new(X, Y, Radius) -> This = slots(X, Y, Radius), spawn(circle, dispatch, [This]). % dispatch the messages for the process as they are received dispatch(This) -> receive {Pid, getx} -> Pid!{retval, getx(This)}, dispatch(This); {Pid, gety} -> Pid!{retval, gety(This)}, dispatch(This); {setx, X} -> dispatch(setx(This, X)); {sety, Y} -> dispatch(sety(This, Y)); {moveto, X, Y} -> dispatch(moveto(This, X, Y)); {rmoveto, X, Y} -> dispatch(rmoveto(This, X, Y)); {Pid, getradius} -> Pid!{retval, getradius(This)}, dispatch(This); {setradius, Radius} -> dispatch(setradius(This,Radius)); {Pid, draw} -> draw(This), Pid!{retval, true}, dispatch(This); dispose -> true end. % get the x & y coordinates for the object getx(This) -> This#circle.x. gety(This) -> This#circle.y. % set the x & y coordinates for the object setx(This, X) -> This#circle{x = X}. sety(This, Y) -> This#circle{y = Y}. % move the x & y position of the object moveto(This, X, Y) -> setx(sety(This, Y), X). rmoveto(This, DeltaX, DeltaY) -> moveto(This, getx(This) + DeltaX, gety(This) + DeltaY). % get the radius of the object getradius(This) -> This#circle.radius. % set the radius of the object setradius(This, Radius) -> This#circle{radius = Radius}. % draw the circle draw(This) -> io:format('Drawing a Circle at:('), io:write(getx(This)), io:format(','), io:write(gety(This)), io:format('), radius '), io:write(getradius(This)), io:format("~n"). |
-module(polymorph). -author('ChrisRathman'). -export([tryme/0]). % test polymorphism in Erlang tryme() -> % create a list containing various shape process instances Scribble = [ rectangle:new(10,20,5,6), circle:new(15,25,8)], % iterate through the list and handle shapes polymorphically drawloop(Scribble), % dispose of the processes disposeloop(Scribble), % call a rectangle specific function ARectangle = rectangle:new(0,0,15,15), ARectangle!{setwidth, 30}, ARectangle!{self(), draw}, retrieve(), ARectangle!dispose, true. % iterate through the list of shapes drawloop([]) -> true; drawloop([Shape|Tail]) -> Shape!{self(), draw}, retrieve(), Shape!{rmoveto, 100, 100}, Shape!{self(), draw}, retrieve(), drawloop(Tail). % close out the object processes disposeloop([]) -> true; disposeloop([Shape|Tail]) -> Shape!dispose, disposeloop(Tail). % wait for process to return result retrieve() -> receive {retval, Any} -> Any end. |
>file:set_cwd('/erlang'). >c('rectangle'). >c('circle'). >c('polymorph'). >polymorph:tryme(). |
Drawing a Rectangle at:(10,20), width 5, height 6 Drawing a Rectangle at:(110,120), width 5, height 6 Drawing a Circle at:(15,25), radius 8 Drawing a Circle at:(115,125), radius 8 Drawing a Rectangle at:(0,0), width 30, height 15 true |