<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 19, 2014 at 10:50 AM, Suraj Kumar <span dir="ltr"><<a href="mailto:suraj.kumar@inmobi.com" target="_blank">suraj.kumar@inmobi.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">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.</blockquote>

</div><br>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</div><div class="gmail_extra">

<br></div><div class="gmail_extra">is_on_point(#shape_a{...}, X,Y) -> ...;</div><div class="gmail_extra">is_on_point(#shape_b{...}, X,Y) -> ...</div><div class="gmail_extra"><br></div><div class="gmail_extra">but this leads to trouble. Naturally, the is_on_point function has to be extended all the time. So make a shape describe itself:</div>

<div class="gmail_extra"><br></div><div class="gmail_extra">-record(shape,</div><div class="gmail_extra">  { repr %% Underlying actual representation, any Erlang term</div><div class="gmail_extra">    is_on_point :: fun( ( term() ) -> boolean())</div>

<div class="gmail_extra">  }).</div><div class="gmail_extra"><br></div><div class="gmail_extra">so:</div><div class="gmail_extra"><br></div><div class="gmail_extra">is_on_point(#shape { is_on_point = IOP, repr = Repr }) -> IOP(Repr).</div>

<div class="gmail_extra"><br></div><div class="gmail_extra">Alternatively, pack up a module in the record, essentially modelling existential types:</div><div class="gmail_extra"><br></div><div class="gmail_extra">-record(shape,</div>

<div class="gmail_extra">  { repr, mod :: atom() }).</div><div class="gmail_extra"><br></div><div class="gmail_extra">is_on_point(#shape { mod = M, repr = R}) -> Mod:is_on_point(R).</div><div class="gmail_extra"><br></div>

<div class="gmail_extra">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.</div>

<div class="gmail_extra"><br></div><div class="gmail_extra">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:</div>

<div class="gmail_extra"><br></div><div class="gmail_extra">Mod:as_set_of_points(V)</div><div class="gmail_extra"><br></div><div class="gmail_extra">for some value V being constructed by Mod and then represent this as</div>

<div class="gmail_extra"><br></div><div class="gmail_extra">-record(sop, { underlying = V, points = [...] }).</div><div class="gmail_extra"><br></div><div class="gmail_extra">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.</div>

<div class="gmail_extra"><br></div><div class="gmail_extra">I guess we will be able to help you better if we know the real data to be modeled.</div><div class="gmail_extra"><br clear="all"><div><br></div>-- <br>J.
</div></div>