<div class="gmail_quote">On 17 February 2012 23:31, Yurii Rashkovskii <span dir="ltr"><<a href="mailto:yrashk@gmail.com">yrashk@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<table cellpadding="0" cellspacing="0" style="border-style:initial;border-color:initial;width:1285px"><tbody style="border-style:initial;border-color:initial"><tr style="border-style:initial;border-color:initial"><td colspan="2" style="border-style:initial;border-color:initial">
<div style="border-style:initial;border-color:initial"><div style="border-style:initial;border-color:initial">Andrew,</div><div class="im"><div style="border-style:initial;border-color:initial"><br></div><div style="border-style:initial;border-color:initial">
>I think a lot of issues with APIs would be solved if we had something analogous to Java interfaces in Erlang. Behaviors just don't cut it. I want something that is a replica of interfaces. Then all the Erlang guys have to do is create the interface and then people can create whatever implementations they want and I never have to worry about changing my code!</div>
<div style="border-style:initial;border-color:initial"><br></div></div><div style="border-style:initial;border-color:initial">I think this new -callback stuff is more apt to solving the problem of interfaces.</div></div><div style="border-style:initial;border-color:initial">
</div><div style="border-style:initial;border-color:initial"></div></td></tr><tr style="border-style:initial;border-color:initial"><td align="right" colspan="2" style="border-style:initial;border-color:initial"></td></tr>
</tbody></table><br></blockquote><div><br></div><div>If I've understood this properly, then the -callback thing will provide a compile time check for the implementors of the callback interface into the custom behaviour, but gives nothing to the (external) client. Now what Andrew and I are looking for in practise, is something roughly like</div>
<div><br></div><div>DbHandle = dbms:bind(pgsql, DriverConfig),</div><div>DbConnection = dbms:connect(DbHandle, dbms:connection_info(Catalog, Schema, AuthMode))</div><div>Results = dbms:execute_query(DbConnection, "select * from foo"),</div>
<div>dbms_result_set:foldl(Results, [], fun collect_foobar/2) </div><div><br></div><div>So I can change 'pgsql' to 'pgsql2' or 'oracle-oci' or 'mysql' or whatever, I can call connect/2 with *any* valid `-opaque db_handle() :: ...' data, call execute_query/2 with *any* valid `-opaque db_connection() :: ...' and I can rely on all implementations returning a structure that I can pass to dbms_result_set foreach/map/foldl and it will 'just work' even if the result set has to have a 'pointer' to those functions or (less tidily) I have to pass the DbHandle to those functions.</div>
<div><br></div><div>Here I can clearly rely on only the 'dbms' API and the people who have to do the heavy lifting are the implementors or 'pgsql' and similar libraries, who have to make sure that their libraries conform to the -callback interface(s) defined by the dbms application. I think though, that there is a question of state that makes this a bit awkward in practise (because even if there are no processes behind the custom behaviour, you still have to maintain the binding to the implementation module(s) somewhere) and also it makes implementing the API more complicated than simply saying 'define these callback functions'. I think this is why so many API efforts (such as simple_bridge) seem to end up using parameterised modules.</div>
<div><br></div><div>A classic example of this is the recent conversation about unifying the dict APIs, but you could apply that to lots of other situations. How can I do that using the -callback approach?</div><div><br></div>
<div>D = dict_api:new(dict | orddict | ....)</div><div>%% add some stuff</div><div>dict_api:find(key1, D2)</div><div><br></div><div>So at a minimum, the implementor of dict_api needs to return (a) the module that implements its -callback interface and (b) whatever state/data that is required in order to fulfil any subsequent call. Now if there was a bit of sugar that allowed me to do this dbms:bind and dict_api:new stuff so that I only need to </div>
<div><br></div><div>1. define the -callback interface somewhere as the API</div><div>2. have a way to get an implementation of the callback interface for any module that provides that -behaviour</div><div><br></div><div>then things would be good right!? But I want this to work without breaking hot loading/upgrades, so I'm not convinced that it's so easy to do when you're effectively spending a lot of time passing around the module name(s) in a bunch of variables or embedded in some records or whatever. What we're looking for is a way to say</div>
<div><br></div><div>%% bind the -callback source to an implementation</div><div>-bind(api_module, implementation_module).</div><div><br></div><div>do_something() -></div><div> api_module:do_something(....)</div><div>
<br></div><div>And make sure that when an upgrade takes place, that what's *really* happening is that the call is being made to 'implementation_module' and any change to 'implementation_module' will trigger a proper code change. I suppose this might be achievable with a parse_transform (that translates from mod_api to the other) but that feels a bit messy and it would be nice for the compiler to check the client code for consistency with the exported -callback API too.</div>
<div><br></div><div>That's probably a terrible approach, but I hope you get the gist of what we're thinking about.</div><div><br></div><div> </div><div> </div><div><br></div></div><br>