Structs
Vladimir Sekissov
svg@REDACTED
Tue Feb 11 20:54:45 CET 2003
Good day,
If you really want or need to code in OO-manner classical dispatching
would be more flexible:
-module(geometry).
new(rectangle, Data) ->
rectangle:new(Data).
width(Obj) ->
Obj(width).
length(Obj) ->
Obj(length).
perimeter(Obj) ->
Obj(perimeter).
-module(rectangle).
-record(rectangle, {width, length}).
new(Config) -> mk_obj(config(#rectangle{}, Config)).
mk_obj(Rectangle) ->
fun (length) ->
length(Rectangle);
(width) ->
width(Rectangle);
(perimeter) ->
perimeter(Rectangle)
end.
config(Rectangle, []) ->
Rectangle;
config(Rectangle, [H | T]) ->
config(config(Rectangle, H), T);
config(Rectangle, {width, N}) when number(N) ->
Rectangle#rectangle{ width = N };
config(Rectangle, {length, N}) when number(N) ->
Rectangle#rectangle{ length = N }.
width(Rectangle) ->
Rectangle#rectangle.width.
length(Rectangle) ->
Rectangle#rectangle.length.
perimeter(Rectangle) ->
2 * (Rectangle#rectangle.width + Rectangle#rectangle.length).
Best Regards,
Vladimir Sekissov
cpressey> Modules I write tend to look a lot like:
cpressey>
cpressey> -module(rectangle).
cpressey>
cpressey> -record(rectangle, {width, length}).
cpressey>
cpressey> new(Config) -> config(#rectangle{}, Config).
cpressey>
cpressey> config(Rectangle, []) ->
cpressey> Rectangle;
cpressey> config(Rectangle, [H | T]) ->
cpressey> config(config(Rectangle, H), T);
cpressey> config(Rectangle, {width, N}) when number(N) ->
cpressey> Rectangle#rectangle{ width = N };
cpressey> config(Rectangle, {length, N}) when number(N) ->
cpressey> Rectangle#rectangle{ length = N }.
cpressey>
cpressey> width(Rectangle) ->
cpressey> Rectangle#rectangle.width.
cpressey> length(Rectangle) ->
cpressey> Rectangle#rectangle.length.
cpressey>
cpressey> perimeter(Rectangle) ->
cpressey> 2 * (Rectangle#rectangle.width + Rectangle#rectangle.length).
cpressey>
cpressey> etc.
cpressey>
cpressey> Of course it varies greatly. When it's a server instead of an inert lump
cpressey> of data, new/1 might be called start/1, and it might spawn a process, with
cpressey> which the other functions might communicate with message sending or
cpressey> gen_server calls. It might also create ets tables. Setting properties
cpressey> might have width/2 and length/2 functions, or a read/2 function, for
cpressey> convenience. The functions might return {ok, Rectangle} or {error,
cpressey> Rectangle} instead of just a new Rectangle. Etc. But it's basically the
cpressey> same.
cpressey>
cpressey> If an external module needs the underlying representation for whatever
cpressey> reason, it can be exported by a function called record_info/1 which wraps
cpressey> around the record_info macro.
cpressey>
cpressey> The association between the names serves to make the grouping adhere: if
cpressey> the module is named rectangle, the instance variables are named
cpressey> Rectangle or RectangleSomething, the ets tables and other global names
cpressey> should be named rectangle too (and the ?MODULE macro makes this easy.)
cpressey>
cpressey> Am I a freak, or do other people find that it helps to write modules this
cpressey> way - basically, to hide each data structure behind interface code?
cpressey> Would structs obsolete this discipline, and if not, how could they be
cpressey> enriched to do so?
cpressey>
cpressey> -Chris
More information about the erlang-questions
mailing list