Part of me questions whether you do really want to raise in such a case, as it feels like defensive programming.
Having said that right now you can do these things: 1. Check that a specific function is exported from a specific module with funtion_exported/3 : https://hexdocs.pm/elixir/Kernel.html#function_exported?/3 If you really wanted to do something like alert the user of the library, you could use that for each function in the behaviour. In fact this might be the best way as there would be no way to tell if a user has (incorrectly) only partly implemented a behaviour. Imagine if they haven’t used `@impl true` for example. 2. Use YourModule.__info__(:functions) and check that way which functions are exported. 3. Use Module.has_attribute?(YourModule, :value) https://hexdocs.pm/elixir/Module.html#has_attribute?/2 <https://hexdocs.pm/elixir/Module.html#has_attribute?/2> and see if the behaviour is listed there. Another option though is for the library to use a protocol instead and define a default implementation for that protocol which raises. Best Adam > On 18 May 2020, at 02:40, Thomas J. <[email protected]> wrote: > > I wish I could edit my messages here :) But passing a user's module to a > library is really common (I had not had my first coffee yet...). > Just looking at the config file should be enough. > > For example: > `config :elixir, :time_zone_database, Tz.TimeZoneDatabase` > > Don't we want to make sure that the module I pass (`Tz.TimeZoneDatabase`) > implements the `Calendar.TimeZoneDatabase` behaviour? And raise if that's not > the case. > Or that the Repo I pass in the config is a valid Repo? Et cetera. > > For example I changed in my config file module `Tz.TimeZoneDatabase` by > `Foo`. And there is no error. Only when I call something like: > `DateTime.shift_zone(~U[2018-07-16 10:00:00Z], "America/Los_Angeles")` > > I will get the error: > `** (UndefinedFunctionError) function > Foo.time_zone_period_from_utc_iso_days/2 is undefined (module Foo is not > available)` > > In my library I would add a function such as `raise_unless_implements/2` to > make sure that the custom module behaves as expected. > > I'm now surprised that this isn't a common practice. > > > On Monday, May 18, 2020 at 2:26:10 AM UTC+2, Thomas J. wrote: > Hello Andrea! > > Imagine, as a library author, that a library module can somehow receive a > module from your application to call functions on. > > E.g. `use LibraryModule, yourModule: Foo` > > `LibraryModule` expect to receive in its `:yourModule` option a module > implementing a certain behaviour. `Foo` is given and the library code wants > to raise an error if the given module doesn't implement the expected > behaviour. > > Actually I thought, that should be pretty common. So I checked in the > dependencies containing large amount of code and configs such as Phoenix, > Ecto, Absinthe, and so on, and guess what, this pattern is almost not used... > > I still found this: > https://hexdocs.pm/ecto/Mix.Ecto.html#ensure_implements/3 > <https://hexdocs.pm/ecto/Mix.Ecto.html#ensure_implements/3> > > > On Sunday, May 17, 2020 at 5:15:08 PM UTC+2, Andrea Leopardi wrote: > Hey Thomas, > > do you have a specific use case in mind to check that a module implements a > behaviour? The fact that you can do this today by getting the module > attributes makes me lean towards not adding this to the standard library, but > I'm curious as to that's the use case you're thinking of :) > > Andrea > > On Sun, May 17, 2020 at 10:41 AM Thomas J. <[email protected] <>> wrote: > Hello, > > What do you think about adding `implements?/2`? > > It accepts two module names as parameters, and it checks if the first > parameter implements the behaviour passed as the second parameter. > > It would execute something like: > > `Enum.member?(Foo.module_info[:attributes][:behaviour], Bar)` > > Only problem I see is that a module can somehow implement a behaviour without > wriring the @behaviour statement. But that could be a documented limitation. > > > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected] <>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/12b5fbff-7460-44c1-81c1-b6710949738e%40googlegroups.com > > <https://groups.google.com/d/msgid/elixir-lang-core/12b5fbff-7460-44c1-81c1-b6710949738e%40googlegroups.com?utm_medium=email&utm_source=footer>. > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected] > <mailto:[email protected]>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/bd8b2a59-a5e2-4e94-a4f3-bcf22fa8e3d3%40googlegroups.com > > <https://groups.google.com/d/msgid/elixir-lang-core/bd8b2a59-a5e2-4e94-a4f3-bcf22fa8e3d3%40googlegroups.com?utm_medium=email&utm_source=footer>. -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/484AFE0F-B6A1-4963-9DC0-C136798520A4%40a-corp.co.uk.
