[erlang-questions] Code complexity and encapsulation
Jesper Louis Andersen
jesper.louis.andersen@REDACTED
Mon May 19 11:33:38 CEST 2014
On Mon, May 19, 2014 at 10:50 AM, Suraj Kumar <suraj.kumar@REDACTED>wrote:
> Thus far, I've gone about modeling each 'shape' as one 'record' in Erlang.
> I've written some 'utility' functions to determine types of various
> records. I've also written boilerplate logic in the 'canvas' class to check
> types and then call appropriate functions. I've also introduced a major
> convention hell which new programmers will have to understand if they want
> to add a new type of shape to the system.
The reason this works in the OO paradigm is because once you have a Shape
S, then calling S.is_on_point(X, Y) lets S reflect on its own shape and
answer the question. In Erlang, we can model this with
is_on_point(#shape_a{...}, X,Y) -> ...;
is_on_point(#shape_b{...}, X,Y) -> ...
but this leads to trouble. Naturally, the is_on_point function has to be
extended all the time. So make a shape describe itself:
-record(shape,
{ repr %% Underlying actual representation, any Erlang term
is_on_point :: fun( ( term() ) -> boolean())
}).
so:
is_on_point(#shape { is_on_point = IOP, repr = Repr }) -> IOP(Repr).
Alternatively, pack up a module in the record, essentially modelling
existential types:
-record(shape,
{ repr, mod :: atom() }).
is_on_point(#shape { mod = M, repr = R}) -> Mod:is_on_point(R).
You are essentially (manually) reimplementing the Subtyping/Open recursion
in Erlang directly with this method. The latter variant can use a behaviour
to make sure the interface is complete. But I wouldn't really do that, it
leads to code which is a maintenance burden.
However, it may be possible to model this differently by dualizing
everything. Rather than thinking in shapes, you might be able to think in
"sets of points with additional information". This means that the code can
always use the set-of-points ignoring the meta-data. In functional
settings, this inversion often yields better data models in the long run.
One trick is to be able to call:
Mod:as_set_of_points(V)
for some value V being constructed by Mod and then represent this as
-record(sop, { underlying = V, points = [...] }).
So you can get back your old V by simply doing SOP#sop.underlying.
Persistence helps a great deal here since having an extra "copy" of V is
free and now you can work with V as if it were a set of points. Smarter
algorithms would also cleverly cull away stuff when you "cast" the V as
another representation so you have to search fewer points, etc. This
solution is somewhat like a view-type for the type of V.
I guess we will be able to help you better if we know the real data to be
modeled.
--
J.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20140519/1c4f9520/attachment.htm>
More information about the erlang-questions
mailing list