<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
span.EmailStyle18
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri",sans-serif;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">Thank you Stanislav for taking the time to iterate. This is nice.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">> Though I am on the side of Alan Kay's definition of the OOP - objects communicating with messages.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">> Anyway, how you "slice" the world and how you make your abstractions - it is influenced by the "classic OOP".<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">> Of course it is very tempting to call behaviour an interface, because it looks like an interface.<o:p></o:p></p>
<p class="MsoNormal">> But it is not because the interface in Erlang are the functions, not a separate entity.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Indeed, but all of the teaching texts are very quick to advocate wrapping your implementations with API calls that delegate to the underlying implementation. This in my mind adds a layer of abstraction on top of pure message passing...
abstractions that play to the weaknesses of "poisoned" practitioners ;)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">That said, your answer does help; thank you again very much!<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I am still not all the way there yet, but at a much better place than a few days ago. My current impression at this point is that the topic is nuanced and perhaps I should be thinking more along the lines of "quit THINKING of behaviours
in terms of interfaces" or more generally, "quit THINIKING in terms of interfaces at all"?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I found it interesting in your example you call `create/1` in main_app at runtime using `DBmod` where my misguided thinking would have tried to use `callbacks_db` instead (interface thinking). ...this might be my disconnect.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">> It is an instrument to remind you to implement functions.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">As I type this I think most of my issues stem from the fear of changing something in the future and not having compile-time checks to help me find all the references (and I saw the behaviour as a nice compile-time check (crutch?) that looked
attractive). This is probably a bigger and different issue all together that I need to learn more about within the Erlang ecosystem. I am assuming it is some combination of supervision, Dialyzer, and really good tests but I am sure I will learn this quite
quickly after deploying some real stuff in the wild... I just would rather learn as much as I can before that time comes.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Thanks,<o:p></o:p></p>
<p class="MsoNormal">Brett<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> Stanislav Ledenev <s.ledenev@gmail.com> <br>
<b>Sent:</b> Wednesday, August 25, 2021 4:04 AM<br>
<b>To:</b> Brett Hemes <brhemes@mmm.com><br>
<b>Cc:</b> erlang-questions@erlang.org<br>
<b>Subject:</b> [EXTERNAL] Re: Re: I am close to using a behaviour as a pure interface and I feel dirty...<o:p></o:p></p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">OK, I'll try to give you my opinion on this topic. If I understand your question correctly. <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">It may look rude but please believe me it is not my intention to be rude.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Your examples for me are the evidence of the "classic OOP" poisoning.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">Remark:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">I call it "classic" based on how the vast majority of the developers perceive the idea of objects and<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">interaction between them. <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">Though I am on the side of Alan Kay's definition of the OOP - objects communicating with messages.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Anyway, how you "slice" the world and how you make your abstractions - it is influenced by the "classic OOP".<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">Erlang is the functional language (more or less) so abstractions are made the other way:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">1. Basic units are Module and Function;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">2. Dynamic function calls - Module:Function(Args). So you can dynamically (in runtime) change the module;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">3. Behaviour is just a hint for a compiler to check a Module for a presence of the required functions.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Based on these 3 points - when you write -behaviour(....) in a module you are just saying that<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">this module must have a bunch of functions implemented to be successfully compiled. It is not for<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">supporting your own abstractions. It is an instrument to remind you to implement functions.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">What you call "general" functionality in Erlang is simply a library implemented as module(s).<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Of course it is very tempting to call behaviour an interface, because it looks like an interface.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">But it is not because the interface in Erlang are the functions, not a separate entity.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Example of using behaviour from my own experience.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">As in almost any application I must have something where I store the data.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">And requirements are very vague. So I don't know if it would be Mnesia, PostgreSQL, file, space station or a toaster.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">So I've made the behaviour which defines functions for my business logic associated with storage.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">To make it simple it is like the CRUD operations on my entities. <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">This behaviour is implemented as an independent rebar3 library, so other parties (sometimes remote) can include it as a dependency.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">But their implementations are included in the final application and what implementation will be used<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">is defined in the configuration file. <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">(Pseudo) code is like this:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">callbacks_db.erl:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> -module(callbacks_db).<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> -callback create(Entity::my_entity_t()) -> ok | {error, Result :: term()}.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">postgresql.erl:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> -module(postgresql).<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> -behaviour(callbacks_db).<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> create(Entity) -> ....<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">toaster_able_to_storage_data.erl:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> -module(toaster_able_to_storage_data).<o:p></o:p></p>
</div>
<div>
<div>
<p class="MsoNormal"> -behaviour(callbacks_db).<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> create(Entity) -> ....<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</div>
<div>
<p class="MsoNormal">main_app.config:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> {main_app, [<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> {db, #{mod => postgresql}} % If you are using a toaster use "toaster_able_to_storage_data"<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> ]}<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">main_app.erl:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> some_function(DBMod) -><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> Entity = create_entity(...),<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> DBmod:create(Entity).<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">That is all about behaviour.<o:p></o:p></p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">ср, 25 авг. 2021 г. в 00:46, Brett Hemes <<a href="mailto:brhemes@mmm.com">brhemes@mmm.com</a>>:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">> Erlang's behaviour is NOT an interface!<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">> If you are looking for some analogy from other languages the closest one is abstract classes in C#.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">This isn’t very helpful... it is the exact same response I find in the forums with no reasoning behind it. I don’t need analogies either; I understand what behaviours are “supposed”
to be from the documentation and comments (perhaps this wasn’t made clear by my post). Where I fall short is “why” are behaviours limited to such and why aren’t more people asking the same questions I am stuck on (regarding polymorphism)? My logic was: yes,
this has been asked and discussed some in the past with no real resolution that I could find... therefore, users must be content/accepting of the tools provided. I am not so naive to think I am the first to need/want such, so there must be a disconnect.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">I posted my example to motivate my questioning hoping for some insight and/or comfort. As of now, I have proceeded with storing “meta refs” to my child servers that are module/reference
tuples (along with some dangerous and future-maintenance-issue-causing assumptions regarding their “interface”)... and it’s works... it just smells, and I am always eager to learn and find the right/better/best way.<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">Aside: a colleague came across this repo (<a href="https://github.com/eldarko/epolymorph" target="_blank">https://github.com/eldarko/epolymorph</a>) while digging and the readme
seems to capture my use case almost exactly...<o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto"> <o:p></o:p></p>
<p class="MsoNormal" style="mso-margin-top-alt:auto;mso-margin-bottom-alt:auto">Brett<o:p></o:p></p>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</body>
</html>