Hi Chris, I think if we follow that reasoning then we won't do anything. Do you know of other problematic issues that you want to share? Perhaps in other topics.
This problem I wrote about is one that exists, and that I believe it deserves some thought. The important thing is to warn the developer when two separated `quote do ... end` blocks inject clauses of the same function/arity. Instead of `defnotoverridable`, a better solution, after discussing with Eric Meadows-Jönsson, could be to do something like defopen [task: 1] after the last clause for task/1 in the first quote block. More generally, the idea is for the compiler to warn when another clause for task/1 is introduced by a different context from that which introduced it first, in case the first context did not ended with a `defopen [task: 1]`; otherwise if it did so, then the compiler does not emit the warning for task/1. I don't know the internals to understand if this is something hard or even feasible to do, but at least, both the problem and a potential solution have been documented. Thanks Mário Guimarães quinta-feira, 21 de Março de 2019 às 17:31:36 UTC, Chris Russo escreveu: > > Once you start down the road of trying to secure included libraries, you > take on a huge responsibility that entails a great deal more low-level > language work. > > On Monday, March 18, 2019 at 12:38:01 PM UTC-4, Mário Guimarães wrote: >> >> Hello, >> >> I would like to propose the addition of a new feature to Elixir. >> >> Suppose a team created the following module >> >> defmodule A do >> defmacro __using__(_opts) do >> quote do >> def task(:coffee), do: "make coffee" >> def task(:cookies), do: "make cookies" >> end >> end >> end >> >> Now, a developer in some other team creates the following module >> >> defmodule MyModule do >> use A >> end >> >> This module allows to make coffe or cookies, and this is a good thing. >> >> Now suppose that after some time, someone else makes finds the next >> module useful >> >> defmodule B do >> defmacro nice_macro() do >> quote do >> def task(x), do: "something good is done, but sometimes there are >> hidden missiles being launched" >> end >> end >> end >> >> and modifies `MyModule` like this >> >> import B >> >> defmodule MyModule do >> use A >> B.nice_macro() >> end >> >> Oops!!! Very bad things can happen now if `MyModule.bar/1` is called with >> anything but `:coffee` or `:cookies`. >> >> This situation can be called an "unexpected clause problem" because it >> makes an existing >> function to be inadvertently redefined by code defined sometime and >> somewhere else. >> >> The proposed solution to this problem is to introduce the >> `defnotoverridable` clause, like this >> >> defmodule A do >> defmacro __using__(_opts) do >> quote do >> def task(:coffee), do: "make coffee" >> def task(:cookies), do: "make cookies" >> defnotoverridable [task: 1] >> end >> end >> end >> >> or like this, by declaring all existing functions at some point to be not >> overridable >> >> defmodule A do >> defmacro __using__(_opts) do >> quote do >> def task(:coffee), do: "make coffee" >> def task(:cookies), do: "make cookies" >> defnotoverridable :all >> end >> end >> end >> >> Note that a `defnotoverridable :all` can also be a strong guarantee >> against a missing `defnotoverridable`, like by doing >> >> defmodule B do >> defmacro __using__(_opts) do >> quote do >> defnotoverridable :all # defend just in case task/1 was previously >> defined at the macro call site >> def task(x), do: "something good is done, but sometimes there are >> hidden missiles being launched" >> end >> end >> end >> >> Furthermore: >> >> 1) a `defnotoverridable` cannot be undone by a subsequent >> `defoverridable`, but a `defoverridable` can be undone by a subsequent >> `defnotoverridable` (the point is, `defoverridable` indicates a >> possibility, whereas `defnotoverridable` indicates an impossibility) >> >> 2) a `defnotoverridable [foo: 1]` requires function `foo/1` to have been >> defined before >> >> I hope you find this addition useful. >> >> Thanks, >> Mário Guimarães >> >> -- 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 elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/74865852-84cc-4c16-8e1a-3ea8e3488a3f%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.