Extending Functionality: an expedient and questionable approach
Chris Pressey
chris_pressey@REDACTED
Thu Mar 13 21:12:51 CET 2003
OK, so I finally got up the courage to ignore the warning in the error_handler documentation, and
hacked error_handler.erl to handle the first iteration of Vlad D.'s proposal - basically, that
delegation/inheritance can be handled at the module level.
Partly this is because I agree that there ought to be something like this or I'll eventually end
up creating too many processes with no good justification for their existence... and also because
I couldn't figure out what the heck was going on in gen_server_2. :)
What it does is this. If you call an undefined function in any module, it looks to see if that
module exports a function called undefined_function/2. If it does, it calls that instead with
(Func, Args) as the arguments. If not, it crashes like usual.
I haven't tested it thoroughly yet, but it seems to work like a charm so far with the
done-to-death example (which probably isn't even good OO modelling in many people's books) of
square being a subclass of rectangle.
I like this because it doesn't really have anything to do with OO. It's like Perl's approach - it
gives you a nice general tool that happens to be useful for implementing a design pattern that
happens to be associated with OO.
So, it is submitted for your peer review. Am I worrying too much about changing
error_handler.erl? (the warning in the man page is pretty dire, but I'm *pretty* sure this is
mostly harmless - but not *totally* sure... you can probably shoot yourself in the foot something
wicked if you call an undefined function from undefined_function/2)
-Chris
------------ <snip> ---------- error_handler.diff
32d31
< crash(Module, Func, Args)
32a32,39
> %% If the module in question exports undefined_function/2, call
> %% it instead of crashing. (this might be very stupid)
> case erlang:function_exported(Module, undefined_function, 2) of
> true ->
> apply(Module, undefined_function, [Func, Args]);
> false ->
> crash(Module, Func, Args)
> end
------------ <snip> ---------- error_handler.diff
------------ <snip> ------------ rectangle.erl
-module(rectangle).
-export([new/0]). % constructors
-export([width/1, width/2, length/1, length/2]). % updatable props
-export([perimeter/1, area/1]). % derived props
-export([print/2]). % methods
-record(rectangle,
{
width = 0,
length = 0
}).
new() ->
#rectangle{}.
width(#rectangle{ width = Width }) ->
Width.
width(Rectangle, Width) when number(Width) ->
Rectangle#rectangle{ width = Width }.
length(#rectangle{ length = Length }) ->
Length.
length(Rectangle, Length) when number(Length) ->
Rectangle#rectangle{ length = Length }.
perimeter(#rectangle{ width = Width, length = Length }) ->
Width * 2 + Length * 2.
area(#rectangle{ width = Width, length = Length }) ->
Width * Length.
print(#rectangle{ width = Width, length = Length }, IoDevice) ->
io:fwrite(IoDevice, "rectangle: ~p x ~p~n", [Width, Length]).
------------ <snip> ------------ rectangle.erl
------------ <snip> -------------- square.erl
-module(square).
-define(SUPER, rectangle).
-export([width/2, length/2]). % updatable props
-export([undefined_function/2]). % inheritance driver
width(Square, Side) ->
?SUPER:length(?SUPER:width(Square, Side), Side).
length(Square, Side) ->
?SUPER:length(?SUPER:width(Square, Side), Side).
undefined_function(Function, Args) ->
apply(?SUPER, Function, Args).
------------ <snip> -------------- square.erl
______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca
More information about the erlang-questions
mailing list