These changes all seem great. I also prefer `@override true` to `@impl true`.
On Thu, Jan 19, 2017 at 1:09 PM, <[email protected]> wrote: > I like all these changes - and I agree with Norbert, I like `@override > true` better than `@impl true` > > But I'm happy to have the functionality whatever the name. +1 > > On Thursday, January 19, 2017 at 4:35:05 AM UTC-8, Norbert Melzer wrote: >> >> This very same post is on elixirforum (https://elixirforum.com/t/beh >> aviours-defoverridable-and-implementations/3338) as well, and I >> commented there. I will post the same comment here and also continue >> discussion here if it happens: >> >> > I really like the idea, but I think that @impl might get confused with >> something related to protocols because of Kernel.defimpl/3, Protocol. >> assert_impl!/2, and Protocol.extract_impls/2 beeing the only things >> mentioning "impl" in elixir until now. Therefore I'd opt for something like >> @override as in Java. >> >> José Valim <[email protected]> schrieb am Do., 19. Jan. 2017 >> um 12:52 Uhr: >> >>> Hi everyone, >>> >>> One of the features added to Elixir early on to help integration with >>> Erlang code was the idea of overridable function definitions. This is what >>> allowed our GenServer definition to be as simple as: >>> >>> defmodule MyServer do >>> use GenServerend >>> >>> Implementation-wise, use GenServer defines functions such as: >>> >>> def terminate(reason, state) do >>> :okend >>> >>> and then mark them as overridable: >>> >>> defoverridable terminate: 2 >>> >>> As the community grew, defoverridable/1 started to show some flaws in >>> its implementation. Furthermore, the community did not always follow up on >>> best practices, often times marking functions as overridable but without >>> defining a proper Behaviour behind the scenes. >>> >>> The goal of this proposal is to clarify the existing functionality and >>> propose extensions that will push the community towards best practices. >>> Using @optional_callbacks >>> >>> In the example above, we have used defoverridable terminate: 2 to make >>> the definition of the terminate/2 function optional. >>> >>> However, in some cases, the use of defoverridable seems to be >>> unnecessary. For instance, we provide a default implementation for >>> handle_call/3 and mark it as overridable, but the default >>> implementation simply raises when invoked. That's counter-intuitive as it >>> would be best to simply not define a default implementation in the first >>> place, truly making the handle_call/3 callback optional. >>> >>> Luckily, Erlang 18 added support for marking callbacks as optional, >>> which we support on Elixir v1.4. We propose Elixir and libraries to >>> leverage this feature and no longer define default implementations for the >>> handle_* functions and instead mark them as optional. >>> >>> Instead of the version we have today: >>> >>> defmodule GenServer do >>> @callback handle_call(message, from, state) >>> >>> defmacro __using__(_) do >>> quote do >>> @behaviour GenServer >>> >>> def handle_call(_message, _from, _state) do >>> raise "handle_call/3 not implemented" >>> end >>> >>> # ... >>> >>> defoverridable handle_call: 3 >>> end >>> endend >>> >>> We propose: >>> >>> defmodule GenServer do >>> @callback handle_call(message, from, state) >>> @optional_callbacks handle_call: 3 >>> >>> defmacro __using__(_) do >>> quote do >>> @behaviour GenServer >>> >>> # ... >>> end >>> endend >>> >>> The proposed code is much simpler conceptually since we are using the >>> @optional_callbacks feature instead of defoverridable to correctly mark >>> optional callbacks as optional. defoverridable will still be used for >>> functions such as terminate/2, which are truly required. >>> >>> For developers using GenServer, no change will be necessary to their >>> code base. The goal is that, by removing unnecessary uses of >>> defoverridable/1, the Elixir code base can lead by example and >>> hopefully push the community to rely less on such tools when they are not >>> necessary. >>> The @impl annotation >>> >>> Even with the improvements above, the usage of defoverridable/1 and >>> @optional_callbacks still have one major downside: the lack of warnings >>> for implementation mismatches. For example, imagine that instead of >>> defining handle_call/3, you accidentally define a non-callback >>> handle_call/2. Because handle_call/3 is optional, Elixir won't emit any >>> warnings, so it may take a while for developers to understand why their >>> handle_call/2 callback is not being invoked. >>> >>> We plan to solve this issue by introducing the @impl true annotation >>> that will check the following function is the implementation of a >>> behaviour. Therefore, if someone writes a code like this: >>> >>> @impl truedef handle_call(message, state) do >>> ...end >>> >>> The Elixir compiler will warn that the current module has no behaviour >>> that requires the handle_call/2 function to be implemented, forcing the >>> developer to correctly define a handle_call/3 function. This is a >>> fantastic tool that will not only help the compiler to emit warnings but >>> will also make the code more readable, as any developer that later uses the >>> codebase will understand the purpose of such function is to be a callback >>> implementation. >>> >>> The @impl annotation is optional. When @impl true is given, we will >>> also add @doc false unless documentation has been given. We will also >>> support a module name to be given. When a module name is given, Elixir will >>> check the following function is an implementation of a callback in the >>> given behaviour: >>> >>> @impl GenServerdef handle_call(message, from, state) do >>> ...end >>> >>> defoverridable with behaviours >>> >>> While @impl will give more confidence and assistance to developers, it >>> is only useful if developers are defining behaviours for their contracts. >>> Elixir has always advocated that a behaviour must always be defined when a >>> set of functions is marked as overridable but it has never provided any >>> convenience or mechanism to enforce such rules. >>> >>> Therefore we propose the addition of defoverridable BehaviourName, >>> which will make all of the callbacks in the given behaviour overridable. >>> This will help reduce the duplication between behaviour and defoverridable >>> definitions and push the community towards best practice. Therefore, >>> instead of: >>> >>> defmodule GenServer do >>> defmacro __using__(_) do >>> quote do >>> @behaviour GenServer >>> >>> def init(...) do ... end >>> def terminate(..., ...) do ... end >>> def code_change(..., ..., ...) do ... end >>> >>> defoverridable init: 1, terminate: 2, code_change: 3 >>> end >>> endend >>> >>> We propose: >>> >>> defmodule GenServer do >>> defmacro __using__(_) do >>> quote do >>> def init(...) do ... end >>> def terminate(..., ...) do ... end >>> def code_change(..., ..., ...) do ... end >>> defoverridable GenServer >>> end >>> endend >>> >>> By promoting new defoverridable API above, we hope library developers >>> will consistently define behaviours for their overridable functions, also >>> enabling developers to use the @impl true annotation to guarantee the >>> proper callbacks are being implemented. >>> >>> PS: Notice defoverridable always comes after the function definitions, >>> currently and as well as in this proposal. This is required because Elixir >>> functions have multiple clauses and if the defoverridable came before, >>> we would be unable to know in some cases when the overridable function >>> definition ends and when the user overriding starts. By having >>> defoverridable at the end, this boundary is explicit. >>> Summing up >>> >>> This proposal promotes the use the of @optional_callbacks, which is >>> already supported by Elixir, and introduces defoverridable(beha >>> viour_name) which will push library developers to define proper >>> behaviours and callbacks for overridable code. >>> >>> We also propose the addition of the @impl true or @impl >>> behaviour_nameannotation, >>> that will check the following function has been listed as a callback by any >>> behaviour used by the current module. >>> >>> Feedback? >>> >>> >>> *José Valim* >>> www.plataformatec.com.br >>> Skype: jv.ptec >>> Founder and Director of R&D >>> >>> -- >>> 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/ms >>> gid/elixir-lang-core/CAGnRm4J2EE%3DvM9k6hz-wsASfYUuTs%2B_ >>> JwRW4cnyFn-eYAcuD0g%40mail.gmail.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4J2EE%3DvM9k6hz-wsASfYUuTs%2B_JwRW4cnyFn-eYAcuD0g%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> For more options, visit https://groups.google.com/d/optout. >>> >> -- > 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/0c46c5d9-3952-49a2-adfb- > 9eae6791eb86%40googlegroups.com > <https://groups.google.com/d/msgid/elixir-lang-core/0c46c5d9-3952-49a2-adfb-9eae6791eb86%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > For more options, visit https://groups.google.com/d/optout. > -- 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/CAN3B1jd_d3ZshY8hpE0eFYx-j5Fd_2dac5_CoB-vrWMYWaVsow%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
