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 |