What's interesting, using metaprogramming techniques available in Elixir, we can do a much better `-extend()` kind of functionality in Elixir:<div><br></div><div>```</div><div>defmodule M do</div><div>  defmacro __using__(_opts) do</div><div>    quote do</div><div>      def hello_world, do: "Hello, world!"</div><div>    end</div><div>  end</div><div>end</div><div>defmodule A do</div><div>  use M</div><div>end<br><div>defmodule B do</div><div>  use M</div><div>end<br></div><div>```<br></div><div><br></div><div>Now, both modules A & B have the same shared hello_world/0 function and it's always exported, and A & B are completed decoupled from M after the compile cycle:</div><div><br></div><div>```</div><div><div>iex(1)> A.hello_world</div><div>"Hello, world!"</div><div>iex(2)> B.hello_world</div><div>"Hello, world!"</div></div><div><div>iex(3)> A.module_info(:exports)   </div><div>[__info__: 1, hello_world: 0, module_info: 0, module_info: 1]</div></div><div><div><div>iex(4)> B.module_info(:exports)   </div><div>[__info__: 1, hello_world: 0, module_info: 0, module_info: 1]</div></div></div><div>```</div><div><br></div><div><br></div>On Tuesday, January 22, 2013 5:55:04 PM UTC-8, Robert Virding wrote:<blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">I agree as well! I think being able to see clearly see what functions a module exports is a rule which we should always follow.<p>Robert</p><p>----- Original Message -----<br>> From: "Loïc Hoguin" <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="JU63uTRG7pcJ">es...@ninenines.eu</a>><br>> To: "Richard O'Keefe" <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="JU63uTRG7pcJ">o...@cs.otago.ac.nz</a>><br>> Cc: "erlang-questions" <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="JU63uTRG7pcJ">erlang-q...@erlang.org</a>><br>> Sent: Wednesday, 23 January, 2013 2:29:55 AM<br>> Subject: Re: [erlang-questions] Is -extends() used in any projects?<br>> <br>> On 01/23/2013 02:09 AM, Richard O'Keefe wrote:<br>> ><br>> > On 22/01/2013, at 7:44 PM, Björn Gustavsson wrote:<br>> ><br>> >> -extends() was mentioned when we first talked<br>> >> about removing parameterized modules, so we<br>> >> assumed that we needed to emulate -extends()<br>> >> as well as parameterized modules.<br>> >><br>> >> It seems to be a good time to ask the question:<br>> >><br>> >> Is -extends() used by real projects? Do we really<br>> >> need to emulate it?<br>> >><br>> >> BTW, -extends() is described here:<br>> >><br>> >>    <a href="http://www.erlang.se/euc/07/papers/1700Carlsson.pdf" target="_blank">http://www.erlang.se/euc/07/<wbr>papers/1700Carlsson.pdf</a><br>> ><br>> > I believe that the design described there takes a wrong<br>> > step on the very first non-title slide:<br>> ><br>> >         All function calls to new_module:f(...)<br>> >         will be redirected to old_module:f(...)<br>> >         if f is *NOT* exported from new_module.<br>> ><br>> > I think that the rule "you may call m:f/n from<br>> > another module if and only if m explicitly<br>> > exports f/n" is an excellent rule.<br>> ><br>> > It means that if you want to know what are the things<br>> > in module m, the information is right there in the<br>> > source code and the beam and if it is loaded,<br>> > module_info gives it to you.<br>> ><br>> > With the design described in those slides, YOU NEVER<br>> > KNOW WHAT THE INTERFACE OF A MODULE (that has an<br>> > -extends in it) IS.<br>> ><br>> > If you *don't* break the module-interfaces-are-knowable<br>> > rule, you get a different design which is entirely<br>> > compile-time (and thus faster):<br>> ><br>> > If f/n is -exported<br>> > and f/n is not defined<br>> > and there is an -extends(m)<br>> > then generate a glue definition<br>> >         f(A1,...,An) -> m:f(A1, ..., An).<br>> ><br>> > It's simple.<br>> > The full interface of a module remains discoverable.<br>> ><br>> > And it's *faster*, because the current design<br>> > requires the lack of a definition to be detected at<br>> > run time, a trap out to a special handler (with the<br>> > arguments packaged into a data structure), time to<br>> > figure out what was undefined, the arguments have to<br>> > be unpacked again, and finally what would have been<br>> > the body of the glue definition is executed.<br>> > To quote Jayne, "where does that get to be fun?"<br>> ><br>> > I once wrote a paper that I couldn't get published.<br>> > It described an object oriented extension to<br>> > Intercal, and it was as deliberately perverse as<br>> > plain Intercal.<br>> ><br>> > This particular attempt to turn Erlang into an OO<br>> > language reminds me very much of that paper, only<br>> > it isn't funny when it's real.<br>> ><br>> > I've built a Smalltalk implementation.  Now Smalltalk<br>> > was originally a single-inheritance language, and its<br>> > dynamic typing means that there are fewer constraints<br>> > on what you can do that way than there are in typical<br>> > typed OO languages.  Even so, there is rather more<br>> > code duplication than I am happy with, and it may be<br>> > this year that I finally add mixins.  (Or it may not.<br>> > There are enough other things to worry about.)  Why<br>> > mention that here?<br>> ><br>> > Because the way -extends is presented in that paper<br>> > means that it can only support single inheritance.<br>> > (Since the ability to determine a module's full<br>> > interface has been destroyed, it cannot handle<br>> >         -extends(p).<br>> >         -extends(q).<br>> > by checking which of p, q defines f/n.)  And that's<br>> > an unjustified limitation.<br>> ><br>> > Change it slightly.  Instead of -extends, use<br>> ><br>> >         -export_from(Other_<wbr>Module, Export_List).<br>> ><br>> > That's just a handy abbreviation form.<br>> >         -export_from(m, [...,f/n,...]).<br>> > means<br>> >         f(A1, ..., An) -> m:f(A1, ..., An).<br>> ><br>> > And now you have multiple inheritance.<br>> > And you have better compile-time checking:  things<br>> > are not re-exported *implicitly*, so if an<br>> > -exported function is not defined in *this* module,<br>> > that's still an error.<br>> ><br>> > And the good part is that because a module's full<br>> > interface is discoverable, you can point your text<br>> > editor at a .beam file and say "generate me a<br>> > -export_from directive from _that_."  (Which should<br>> > be done by calling a little command-line tool:<br>> > generating an -export_from directive doubles very<br>> > nicely as a way for a human to find out what a module<br>> > exports without having to read the source code, which<br>> > they might not have anyway.)<br>> <br>> Agree with everything.<br>> <br>> Thanks ROK for always making amazingly clear explanations.<br>> <br>> --<br>> Loïc Hoguin<br>> Erlang Cowboy<br>> Nine Nines<br>> <a href="http://ninenines.eu" target="_blank">http://ninenines.eu</a><br>> ______________________________<wbr>_________________<br>> erlang-questions mailing list<br>> <a href="javascript:" target="_blank" gdf-obfuscated-mailto="JU63uTRG7pcJ">erlang-q...@erlang.org</a><br>> <a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/<wbr>listinfo/erlang-questions</a><br>> <br>______________________________<wbr>_________________<br>erlang-questions mailing list<br><a href="javascript:" target="_blank" gdf-obfuscated-mailto="JU63uTRG7pcJ">erlang-q...@erlang.org</a><br><a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/<wbr>listinfo/erlang-questions</a><br></p><p></p></blockquote></div>