Module inheritance

1,001 views
Skip to first unread message

Oren Ben-Kiki

unread,
Jan 28, 2013, 3:53:46 PM1/28/13
to elixir-l...@googlegroups.com
Erlang supports the `-extends` attribute to implement module-level inheritance (http://www.erlang.se/euc/07/papers/1700Carlsson.pdf provides a good description). Is there an equivalent in Elixir?

Yurii Rashkovskii

unread,
Jan 28, 2013, 3:56:34 PM1/28/13
to elixir-l...@googlegroups.com
They are actually changing this in favor of $handle_undefined function. I personally find macro-generated modules with overlapping functionality a better fit.


On Mon, Jan 28, 2013 at 12:53 PM, Oren Ben-Kiki <or...@ben-kiki.org> wrote:
Erlang supports the `-extends` attribute to implement module-level inheritance (http://www.erlang.se/euc/07/papers/1700Carlsson.pdf provides a good description). Is there an equivalent in Elixir?

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group, send email to elixir-lang-co...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Oren Ben-Kiki

unread,
Jan 28, 2013, 4:04:04 PM1/28/13
to elixir-l...@googlegroups.com
$handle_undefined_function would incur an additional run-time operation, correct?

It isn't clear to me how macros could deal with selectively overriding some of the "base" function.


To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Yurii Rashkovskii

unread,
Jan 28, 2013, 4:04:24 PM1/28/13
to elixir-l...@googlegroups.com
Oren,


But I personally would prefer not to use this feature in Elixir... What we can do instead is something like...

```elixir
defmodule Common do
  defmacro __using__(_) do
    quote do
       def common, a: 1
    end
  end
end
defmacro A do
  use Common
end
defmacro B do
  use Common
end
```

However, there are cases when you'd want to use that undefined function handler, when you actually don't have a parent you want to relay to.

Yurii Rashkovskii

unread,
Jan 28, 2013, 4:05:23 PM1/28/13
to elixir-l...@googlegroups.com
Yeah, see my previous message with an example. And if you want to override any of the "base" functions, simply do

```elixir
defoverridable [name: arity]
```

Oren Ben-Kiki

unread,
Jan 28, 2013, 4:19:08 PM1/28/13
to elixir-l...@googlegroups.com
Hmmm. I wasn't aware of defoverridable. I guess that would work. It isn't as elegant as `-extends` but I guess that depends on whether one is actually trying to encourage this sort of thing... At any rate, I'll give it a whirl and see how well it works for me.

Thanks!

José Valim

unread,
Jan 28, 2013, 4:19:54 PM1/28/13
to elixir-l...@googlegroups.com
I don't particularly encourage extends but it can be easily achieved as:


José Valim
Skype: jv.ptec
Founder and Lead Developer

Oren Ben-Kiki

unread,
Jan 28, 2013, 4:29:50 PM1/28/13
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br
I agree this should be used very sparingly; in my case, there's a single specific case I want to use it for in my system. That said, it is much cleaner to do it the way you provided - thanks!

Oren Ben-Kiki

unread,
Feb 1, 2013, 1:09:07 PM2/1/13
to elixir-l...@googlegroups.com, José Valim
A correction: 1..arity doesn't work when arity is 0 (it actually generates [1,0] instead of []). Is this the expected behavior?


--

Yurii Rashkovskii

unread,
Feb 1, 2013, 1:10:24 PM2/1/13
to elixir-l...@googlegroups.com

It is. It was the other way around some time ago

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

José Valim

unread,
Feb 1, 2013, 4:57:12 PM2/1/13
to elixir-l...@googlegroups.com
The current behaviour is correct. Ideally we would have "excluding end" ranges, but we don't. I have updated the gist to consider zero arity functions:

https://gist.github.com/ff41078606cfe0e55eaf


José Valim
Skype: jv.ptec
Founder and Lead Developer


Oren Ben-Kiki

unread,
Mar 15, 2013, 9:18:38 PM3/15/13
to elixir-l...@googlegroups.com
Using the gist that Jose has posted, there seems to be a problem with indirect function calls; it seems that somehow the version from the base module is invoked, even though all the functions are declared as delegates and overridable. The following https://gist.github.com/orenbenkiki/5174435 demonstrates the problem.

If I recall correctly, the Erlang module inheritance mechanism does behave correctly in such a case. Is there an Elixir workaround to provide this?

José Valim

unread,
Mar 15, 2013, 9:34:35 PM3/15/13
to elixir-l...@googlegroups.com
Hrm, I cannot think of any easy work around for now, sorry.

I'd also be surprised if the Erlang implementation worked given their current implementation. I would have to investigate it later.



José Valim
Skype: jv.ptec
Founder and Lead Developer


On Fri, Mar 15, 2013 at 7:18 PM, Oren Ben-Kiki <or...@ben-kiki.org> wrote:
Using the gist that Jose has posted, there seems to be a problem with indirect function calls; it seems that somehow the version from the base module is invoked, even though all the functions are declared as delegates and overridable. The following https://gist.github.com/orenbenkiki/5174435 demonstrates the problem.

If I recall correctly, the Erlang module inheritance mechanism does behave correctly in such a case. Is there an Elixir workaround to provide this?

--

Oren Ben-Kiki

unread,
Mar 16, 2013, 1:10:15 PM3/16/13
to elixir-l...@googlegroups.com
I updated the gist: https://gist.github.com/orenbenkiki/5174435 to demonstrate a possible workaround based on protocols. It seems to work, but I'm not certain this is the most elegant solution...

For example, it would have been nice to be able to get rid of the `{}` surrounding the invoked module name, and to pack the `implements` directive inside the module instead of after it. Alternatively, it might have been possible to adapt the `extends` macro so having one record extend another would work without warnings.

There's also the use of an AST instead of `quote` in the macro, I'm not certain whether there's a nicer way to achieve the desired effect. 

At any rate, if we don't want to encourage "module inheritance", this workaround may suffice.

José Valim

unread,
Mar 16, 2013, 1:27:38 PM3/16/13
to elixir-l...@googlegroups.com
This macro implementation worked here:

  defmacro implements(module, protocol: protocol) do
    quote do
      defimpl unquote(protocol), for: unquote(module) do
        import Extension
        extends unquote(module)
      end
    end
  end



José Valim
Skype: jv.ptec
Founder and Lead Developer


--

Oren Ben-Kiki

unread,
Mar 16, 2013, 2:06:12 PM3/16/13
to elixir-l...@googlegroups.com
Of course <smack self on head>. I updated the gist accordingly.

Thanks,

Oren Ben-Kiki

boris kotov

unread,
May 27, 2018, 5:14:13 PM5/27/18
to elixir-lang-core
Hey José,

I am the guy, who just asked about defdelegate (n-ary) (if you still can remember)
And what I was actually looking for is `extends SomeModule` feature, instead of delegating all functions one-by-one * arity.

Just wondering, why this feature is still not in the core :) ?

Thanks,
Boris

José Valim

unread,
May 27, 2018, 5:23:44 PM5/27/18
to elixir-l...@googlegroups.com
Hi Boris,

Simply because it is a pattern we don't want to encourage, as it fully couples a module to another one.

And there are questions such as documentation. Are you going to document the delegated functions? If not, why not? Should we copy the delegations? Then the examples are likely outdated.

If you feel like you need to delegate a whole module, it is better to re-evaluate the solution and discuss the problem, as it is very unlikely in Elixir.



José Valim
Skype: jv.ptec
Founder and Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/e6a44f9f-a62f-44f2-9e75-1ebec3d298d8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

boris kotov

unread,
May 27, 2018, 6:20:13 PM5/27/18
to elixir-lang-core
No, I meant this as a language feature, for users, to re-use functionalities from other modules by extending them.
For sure, if you are going to extend something, you should know what the origin is doing, and why you are extending it.
I am thinking about some community packages, where some of your special use-cases are not covered, and you would like to "extend" it, not fully reimplement it.
The same goes for already existing erlang packages, where you want to touch some parts and let the rest do its job.
IMHO "use" is actually meant for this kind of extension, but its very strict and limited by the actual implementation, which is good actually.
Extend on the other hand would be more flexible, which also a good thing :)

Documentation, I see, might be a problem, if you want to publish it. I am not sure, but I think it should be possible to take the current documentation from the origin on the fly while compiling, maybe I am wrong.

Am Sonntag, 27. Mai 2018 23:23:44 UTC+2 schrieb José Valim:
Hi Boris,

Simply because it is a pattern we don't want to encourage, as it fully couples a module to another one.

And there are questions such as documentation. Are you going to document the delegated functions? If not, why not? Should we copy the delegations? Then the examples are likely outdated.

If you feel like you need to delegate a whole module, it is better to re-evaluate the solution and discuss the problem, as it is very unlikely in Elixir.



José Valim
Skype: jv.ptec
Founder and Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Louis Pilfold

unread,
May 27, 2018, 6:44:31 PM5/27/18
to elixir-l...@googlegroups.com
Hi Boris

Regardless of whether this functionality is desirable, one could implement functionality like this using Elixir's macro system. As such there is no need for it to be a core language feature.

If you want it why not implement it and release it as a Hex package? That way you get the feature you want, and of it proves to be useful others can also make use of it too.

Cheers,
Louis

boris kotov

unread,
May 27, 2018, 7:00:38 PM5/27/18
to elixir-lang-core
Hi Louis,

yeah you are right, its something that I am already thinking about.
I was just wondering, what are the cons of putting it directly into the language, as it seems to me, to be a core-language-feature.

Cheers,
Boris

Steve Morin

unread,
May 27, 2018, 7:10:15 PM5/27/18
to elixir-l...@googlegroups.com
Feels too much like an inheritance pattern that I don’t think makes sense in a clean functional style.  I can see uses for it but feel like it will be abused more than it will help.

Steve Morin

unread,
May 27, 2018, 7:11:11 PM5/27/18
to elixir-l...@googlegroups.com
Re:my prior comments, think it would be good as a add on package for those that want to use that.

Louis Pilfold

unread,
May 27, 2018, 7:23:16 PM5/27/18
to elixir-l...@googlegroups.com
Hey

I'd say the disadvantage is that it'd be making Elixir a bigger and more complex language. I think there's value in having a small core language that gives users the tools to extend it as required.

And there's always the question what exactly should be a core feature. I don't use any languages that support inheritance, and thus to be this seems like an exotic niche feature rather than a core language feature. :)

Cheers,
Louis

OvermindDL1

unread,
May 31, 2018, 6:42:32 PM5/31/18
to elixir-lang-core
OCaml, a functional language, has the `include` keyword that does something very much like this proposal.

OCaml's `include SomeModule` will take the entire public API of that module and plop it right at the location it is called in this file (properly typechecked and all of course) delegating to the other module.  At this point you can redefine some of the functions that were included and/or add to the API by making new functions.  At this point you can just `open MySomeModule` and use it just like `open SomeModule`.  You can include multiple modules to make a new 'integration' module.  It is exceptionally useful because the types that get mixed in are fully the same type as the original module.

It's use-case in the OCaml world is not inheritance (by any stretch, it happens statically after all), but rather as a form of mixins or API combiner (to let the user open a single API module instead of opening 50 or so).

But OCaml's `include` is like it's `open` (which is like Elixir's `import`) except it also re-exposes it all out of the module's public interface that it was included within.

Do note, this is significantly different from textual including ala C-style macro's, OCaml's is really very similar to an Elixir Macro that just iterates over the public API of another module and just delegates everything to it.

But yes, this could easily just be a hex package, it would not even be a complicated one, but it would be a great first-time macro project for someone.  :-)

boris kotov

unread,
Jun 2, 2018, 6:34:40 AM6/2/18
to elixir-lang-core
I did some experiments, and unfortunately module.__info__(:docs) is not supported anymore. Did I missed something? Is there maybe something like module.func.__info__(:doc) ?

José Valim

unread,
Jun 2, 2018, 6:46:13 AM6/2/18
to elixir-l...@googlegroups.com
I think __info__(:doc) was available a long time ago? Anyway, the docs today are stored in separate BEAM chunk and with Elixir v1.7 we are moving to EEP 48: http://erlang.org/eeps/eep-0048.html



José Valim
Skype: jv.ptec
Founder and Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/7ab9d547-6581-4079-8337-cc1c9d880af2%40googlegroups.com.

boris kotov

unread,
Jun 2, 2018, 6:50:17 AM6/2/18
to elixir-lang-core
Ah, alright, thanks for the insight )

Torben Hoffmann

unread,
Jun 4, 2018, 2:54:59 PM6/4/18
to elixir-l...@googlegroups.com
Please remember that the core building blocks on the BEAM are processes. Modules are mostly there to keep related code in the same place.

There was module inheritance in Erlang at one point - it has been removed. Evolution weeded it out.

Cheers,
Torben


For more options, visit https://groups.google.com/d/optout.
--
Reply all
Reply to author
Forward
0 new messages