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/a72a057b-35db-414b-8f15-43952420910c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to