Extending Functionality: an expedient and questionable approach

Chris Pressey <>
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