New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Complete typespecs and guards for Module module #5869
Complete typespecs and guards for Module module #5869
Conversation
67e7dfe
to
0f70502
Compare
lib/elixir/lib/module.ex
Outdated
@@ -725,7 +733,7 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
def defines?(module, tuple) when is_tuple(tuple) do | |||
def defines?(module, tuple) when is_atom(module) and is_tuple(tuple) and tuple_size(tuple) == 2 do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do defines?(module, {_, _} = tuple) when is_atom(module)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great!
besides being neater, does it perform faster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perf diff is negligent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean negligible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hahahahaha, yes
lib/elixir/lib/module.ex
Outdated
@@ -749,7 +757,9 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
def defines?(module, tuple, kind) do | |||
@spec defines?(module, {function_name :: atom, arity}, :def | :defp | :defmacro | :defmacrop) :: boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do defines?(module, {_, _} = tuple, ...) when is_atom(module)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed and improved
@eksperimental yup, a new type would be super helpful here. |
4f15863
to
e543c8e
Compare
@josevalim so what should we name it?
|
@eksperimental |
you mean |
I meant |
@josevalim that is not documented in Elixir, and in Erlang |
@eksperimental IIRC it didn't used to be documented in Erlang and when it wasn't documented it meant |
So let's go with |
thank you @fishcakez, interesting and ambiguous. |
So it is documented at since OTP-17.4 |
Please let us know when this is ready for another pass. |
sorry @josevalim, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few spec changes, and I suggested a few spec changes for completeness.
I am not sure I am a fan of these PRs adding guards everywhere. If I was writing the code fresh I would not put them because I am not sure they add value and make the code unnecessarily verbose. Maybe I am missing something but it feels like busy work to me. Is there a issue/email/comment detailing the goal of doing this?
lib/elixir/lib/module.ex
Outdated
@@ -1015,7 +1040,8 @@ defmodule Module do | |||
@doc false | |||
# Used internally to compile types. | |||
# This function is private and must be used only internally. | |||
def store_typespec(module, key, value) when is_atom(key) do | |||
@spec store_typespec(module, key :: atom, value :: term) :: Keyword.t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function returns true
, not Keyword.t
.
Personally I think adding type checking guards to internal functions like this one is too defensive. Normally type check on boundary and use guards for flow control internally.
Is there reason spec'ed this undocumented function and not the other two (get/put attribute)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is @doc false
, I agree. No need or specs nor guards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spec removed
lib/elixir/lib/module.ex
Outdated
@@ -463,7 +467,7 @@ defmodule Module do | |||
""" | |||
def create(module, quoted, opts) | |||
|
|||
def create(module, quoted, %Macro.Env{} = env) do | |||
def create(module, quoted, %Macro.Env{} = env) when is_atom(module) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create/3
is missing spec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. please review it
lib/elixir/lib/module.ex
Outdated
@@ -550,18 +554,19 @@ defmodule Module do | |||
|
|||
""" | |||
@spec safe_concat(binary | atom, binary | atom) :: atom | no_return | |||
def safe_concat(left, right) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be :: atom
, no no_return
, could you fix this as you are fixing the other specs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
lib/elixir/lib/module.ex
Outdated
@@ -788,7 +806,8 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
def definitions_in(module, kind) do | |||
@spec definitions_in(module, atom) :: [function_arity] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is atom too general? Perhaps the different kinds could have their own types and reused throughout the specs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. it's a good idea. done!
lib/elixir/lib/module.ex
Outdated
@@ -801,14 +820,16 @@ defmodule Module do | |||
developer to customize it. See `Kernel.defoverridable/1` for | |||
more information and documentation. | |||
""" | |||
def make_overridable(module, tuples) do | |||
@spec make_overridable(module, [function_arity]) :: :ok | no_return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be :: :ok
, no no_return
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still the no_return
here 😕
lib/elixir/lib/module.ex
Outdated
@@ -970,6 +994,7 @@ defmodule Module do | |||
["Very", "Long", "Module", "Name", "And", "Even", "Longer"] | |||
|
|||
""" | |||
@spec split(module) :: [String.t] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will return non-empty list of strings: [String.t, ...]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
So the guards will cause an immediate function clause error on bad
arguments. This should help users fix bugs in their code without needing to
read the source of elixir. It is especially to improve experience for new
users who won't be familiar with debugging elixir or know where to look.
…On 16 Mar 2017 12:03 pm, "José Valim" ***@***.***> wrote:
***@***.**** approved this pull request.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#5869 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AB6JTfgsn1lG48Tyys0lhAJ9CkfhNoWOks5rmST8gaJpZM4MbYaB>
.
|
suggestions added, please review them. |
lib/elixir/lib/module.ex
Outdated
@spec defines?(module, function_arity) :: boolean | ||
def defines?(module, {function_macro_name, arity} = tuple) | ||
when is_atom(module) and is_atom(function_macro_name) | ||
and is_integer(arity) and arity >= 0 and arity <= 255 do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put the and
at the end of the previous line, and indent is_integer
to be aligned with the is_atom
on the line above:
def ...
when is_atom(module) and is_atom(function_macro_name) and
is_integer(arity) and arity >= 0 ... do
lib/elixir/lib/module.ex
Outdated
@spec defines?(module, function_arity, def_kind) :: boolean | ||
def defines?(module, {function_macro_name, arity} = tuple, def_kind) | ||
when is_atom(module) and is_atom(function_macro_name) | ||
and is_integer(arity) and arity >= 0 and arity <= 255 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/elixir/lib/module.ex
Outdated
@@ -801,14 +820,16 @@ defmodule Module do | |||
developer to customize it. See `Kernel.defoverridable/1` for | |||
more information and documentation. | |||
""" | |||
def make_overridable(module, tuples) do | |||
@spec make_overridable(module, [function_arity]) :: :ok | no_return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still the no_return
here 😕
I honestly feel a bit like @fishcakez, this PR is quite "heavy" on the verboseness side. I understand the point in doing this but I can't shake off the bad feeling |
To be honest, I'm not very keen on adding guards everywhere. They should be considered more closely, since they don't always improve errors. For example with |
@michalmuskala we should revisit such cases then but I would say that's rather the exception than the rule. We should probably consider reverting the function guards there. Other cases where we typically raise good messages is when using maps. Other than that, it is most likely that the error message will be bad. For example, an unchecked tuple can potentially raise badarg when calling element three or for function calls inside. That's arguably a worst experience. For what is worth, most of the API in OTP is correctly guarded. In Elixir we never had the habit. So overall the rationale is to provide better documentation and error messages. I agree the system is verbose and I don't like it either but if it improves the language experience with more documentation and error messages, then I think it is worth it. |
c0e97f7
to
8f6044f
Compare
@whatyouhide corrections made |
e09f344
to
325ba79
Compare
lib/elixir/lib/module.ex
Outdated
Module.definitions_in __MODULE__, :def #=> [{:version, 0}] | ||
Module.definitions_in __MODULE__, :defp #=> [] | ||
Module.definitions_in __MODULE__, :defmacro #=> [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change? If you change version/0
to be a macro, then Module.definitions_in(__MODULE__, :def)
will return []
, not [{:version, 0}]
, and :defmacro
will return [{:version, 0}]
instead 😕
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was probably figuring out the spec and played with the example and accidentally saved it.
lib/elixir/lib/module.ex
Outdated
end | ||
|
||
""" | ||
def definitions_in(module, kind) do | ||
@spec definitions_in(module, def_kind) :: [function_arity] | ||
def definitions_in(module, def_kind) when is_atom(module) and is_atom(def_kind) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have the usual when def_kind in [:def, defp, ...]
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
lib/elixir/lib/module.ex
Outdated
Module.LocalsTracker.yank(module, tuple) | ||
:lists.foreach(fn | ||
{function_name, arity} = tuple | ||
when is_atom(function_name) and is_integer(arity) and arity >= 0 and arity <= 255 -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please indent this on the same line as the lone above. It's not that long, but this indentation looks a bit off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean move it to the line above, or indent it to the same level as the line above?
lib/elixir/lib/module.ex
Outdated
Module.LocalsTracker.yank(module, tuple) | ||
end | ||
|
||
old = :elixir_overridable.overridable(module) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we drop the =
alignment since we're touching these lines?
lib/elixir/lib/module.ex
Outdated
@@ -879,8 +910,8 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
@spec get_attribute(module, atom) :: term | |||
def get_attribute(module, key) do | |||
@spec get_attribute(module, key :: atom) :: (value :: term) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to name the types here (key ::
and value ::
), they're clear from the function arguments and the function docs.
35ad2a2
to
189f4c5
Compare
lib/elixir/lib/module.ex
Outdated
@@ -351,6 +351,10 @@ defmodule Module do | |||
the documentation for the [`:compile` module](http://www.erlang.org/doc/man/compile.html). | |||
''' | |||
|
|||
@type function_arity :: {atom, arity} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make those typep
as I don't want others to depend on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed function_arity
, def_kind
, type_kind
to private.
lib/elixir/lib/module.ex
Outdated
kind in [:def, :defmacro, :type, :opaque] and (is_binary(doc) or is_boolean(doc) or doc == nil) do | ||
def add_doc(module, line, kind, function_tuple, signature, doc) | ||
when kind in [:def, :defmacro, :type, :opaque] | ||
and (is_binary(doc) or is_boolean(doc) or doc == nil) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And should be in the previous line and the parens should be aligned with the beginning of kind
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
lib/elixir/lib/module.ex
Outdated
@spec defines?(module, function_arity, def_kind) :: boolean | ||
def defines?(module, {function_macro_name, arity} = tuple, def_kind) | ||
when is_atom(module) and is_atom(function_macro_name) and | ||
is_integer(arity) and arity >= 0 and arity <= 255 and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't arity in 0..255
work here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. They wouldn't work at this point. Ranges work different than lists with in
.
lib/elixir/lib/module.ex
Outdated
end | ||
other -> | ||
raise ArgumentError, | ||
"each element in tuple list has to be a {function_name :: atom, arity :: 1..255} tuple, got: #{inspect(other)}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arity is from 0 to 255.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you. fixed
lib/elixir/lib/module.ex
Outdated
def overridable?(module, tuple) do | ||
@spec overridable?(module, function_arity) :: boolean | ||
def overridable?(module, {function_name, arity} = tuple) | ||
when is_atom(function_name) and is_integer(arity) and arity >= 0 and arity <= 255 do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arity in 0..255
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't work.
lib/elixir/lib/module.ex
Outdated
@@ -879,8 +910,8 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
@spec get_attribute(module, atom) :: term | |||
def get_attribute(module, key) do | |||
@spec get_attribute(module, atom) :: (term) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove parens around term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you
lib/elixir/lib/module.ex
Outdated
@@ -897,8 +928,8 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
@spec delete_attribute(module, key :: atom) :: (value :: term) | |||
def delete_attribute(module, key) when is_atom(key) do | |||
@spec delete_attribute(module, atom) :: (term) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove parens around term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
lib/elixir/lib/module.ex
Outdated
@@ -944,18 +975,20 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
def register_attribute(module, new, opts) when is_atom(new) do | |||
@spec register_attribute(module, attribute :: atom, opts :: [{:accumulate, boolean}, {:persist, boolean}]) | |||
:: :ok | no_return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove no_return
from here per the previous discussions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -310,4 +316,33 @@ defmodule ModuleTest do | |||
assert Module.definitions_in(__MODULE__, :defp) == [] | |||
end | |||
end | |||
|
|||
describe "make_overridable/2 arguments" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check lib/elixir/test/elixir/kernel/overridable_test.exs. We don't need to add the success test because there are many there. You can add a test for the error in make_overridable though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. have a look please.
@josevalim All your suggestions have been implemented |
Sorry but I can't see why the range version wouldn't work. arity in 0..255
expands to exactly the same code you wrote.
--
*José Valimwww.plataformatec.com.br
<http://www.plataformatec.com.br/>Founder and Director of R&D*
|
Well, I originally did it that way and I had to change it because it wouldn't work. (second line is the offending line no. 743) def defines?(module, {function_macro_name, arity} = tuple)
when is_atom(module) and is_atom(function_macro_name) and arity in 0..255 do
assert_not_compiled!(:defines?, module)
table = defs_table_for(module)
:ets.lookup(table, {:def, tuple}) != []
end
|
Ah, that's because of bootstrapping. Ok. Let's go as is.
|
lib/elixir/lib/module.ex
Outdated
should be omitted for types) and the documentation, which should | ||
be either a binary or a boolean. | ||
It expects the module the function/type belongs to, the line (a non-negative integer), | ||
the kind (`:def`, `defmacro`, `:type`, `:opaque`), a tuple `{<function atom>, <arity>}`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:defmacro
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function atom
reads oddly, I think we can say function name
instead.
lib/elixir/lib/module.ex
Outdated
@@ -351,6 +351,10 @@ defmodule Module do | |||
the documentation for the [`:compile` module](http://www.erlang.org/doc/man/compile.html). | |||
''' | |||
|
|||
@typep function_arity :: {atom, arity} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe function_arity_pair
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can name it definition
, as it this name is already used in definitions_in
function, which returns in exactly that format.
lib/elixir/lib/module.ex
Outdated
@@ -725,7 +738,10 @@ defmodule Module do | |||
end | |||
|
|||
""" | |||
def defines?(module, tuple) when is_tuple(tuple) do | |||
@spec defines?(module, function_arity) :: boolean | |||
def defines?(module, {function_macro_name, arity} = tuple) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function_macro_name
seems quite confusing to me, can we just say function_name
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, we use function_name
in same context in make_overridable
, and overridable?
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am worried that function_name
doesn't take macros. That's why the difference.
We could name it function_or_macro_name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 for clarity, let's go with function_or_macro_name
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
assert_not_compiled!(:defines?, module) | ||
table = defs_table_for(module) | ||
case :ets.lookup(table, {:def, tuple}) do | ||
[{_, ^kind, _, _, _, _}] -> true | ||
[{_, ^def_kind, _, _, _, _}] -> true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should keep kind
, we didn't change that in add_doc
as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is done intentionally, to be inlined with the typep
s:
in add_doc is called kind
because its typespec is a union def_kind | type_kind
assert_not_compiled!(:definitions_in, module) | ||
table = defs_table_for(module) | ||
:lists.concat :ets.match(table, {{:def, :'$1'}, kind, :_, :_, :_, :_}) | ||
:lists.concat :ets.match(table, {{:def, :'$1'}, def_kind, :_, :_, :_, :_}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/elixir/lib/module.ex
Outdated
Module.LocalsTracker.yank(module, tuple) | ||
end | ||
|
||
old = :elixir_overridable.overridable(module) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra space here to ✂️.
@@ -310,4 +316,19 @@ defmodule ModuleTest do | |||
assert Module.definitions_in(__MODULE__, :defp) == [] | |||
end | |||
end | |||
|
|||
test "make_overridable/2 with bad arguments" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we usually use invalid
instead of bad
.
@@ -50,11 +50,17 @@ defmodule ModuleTest do | |||
end | |||
Module.eval_quoted __MODULE__, contents, [], file: "sample.ex", line: 13 | |||
|
|||
defp purge(modules) do | |||
Enum.each modules, fn(m) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems premature use of Enum
here, in places where we call purge/1
helper we pass only one module.
lib/elixir/lib/module.ex
Outdated
def register_attribute(module, new, opts) when is_atom(new) do | ||
@spec register_attribute(module, attribute :: atom, opts :: [{:accumulate, boolean}, {:persist, boolean}]) | ||
:: :ok | ||
def register_attribute(module, attribute, opts) when is_atom(module) and is_atom(attribute) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we're fine to rename opts
–> options
?
@lexmag I have added a commit with your suggestions. I didn't add implement since I have left a comment waiting for your answer. |
this is ready to merge. |
Thanks @eksperimental! 💟 |
thank you everyone (@elixir-lang/elixir) for your suggestions! |
There are plenty of changes, that's why the [WIP], but it all guards and typespecs are complete for this module.
There is a common argument which is the
{<function/macro atom>, <arity>}
tuple,and it make me think whether we need to create a new
type
for this.