What does `Any` in Elixir `defprotocol` actually contains?
-
23-12-2019 - |
Question
My blank.ex is :
defprotocol Blank do
@fallback_to_any true
def blank?(data)
end
defimpl Blank, for: Any do
def blank?(_), do: false
end
and I type in iex, the output is:
iex(18)> Blank.blank? []
true
iex(19)> Blank.blank? [6]
false
iex(20)> Blank.blank? '12'
false
iex(22)> Blank.blank? "' "
true
iex(23)> Blank.blank? "elixi"
true
iex(24)> Blank.blank? {1}
true
iex(25)> Blank.blank? {1, 2}
true
iex(26)> Blank.blank? 2
false
So I'm wondering what does the Any
means in this context? and I got something interesting, weather or not I use the implemented like this
defimpl Blank, for: Any do
def blank?(_), do: false
end
and the output in the iex before it's the same. Does that means this implemented does nothing? Or I have missed something?
Solution
Any
clause should be called if an implementation is not provided.
I don't know why you're getting these weird results, but I suspect you have some incorrect definitions in the shell session. I have tried with the example from the site:
defprotocol Blank do
@fallback_to_any true
def blank?(data)
end
defimpl Blank, for: Integer do
def blank?(_), do: false
end
# Just empty list is blank
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
# Just the atoms false and nil are blank
defimpl Blank, for: Atom do
def blank?(false), do: true
def blank?(nil), do: true
def blank?(_), do: false
end
defimpl Blank, for: Any do
def blank?(_), do: false
end
And got expected results:
iex(1)> Blank.blank? "' "
false
iex(2)> Blank.blank? "elixi"
false
iex(3)> Blank.blank? []
true
iex(4)> Blank.blank? {} # fallback to Any
false
The last example is a fallback to Any
, since the protocol is not defined for a tuple. If you remove the Any
implementation, and restart the shell, you should get an error:
iex(1)> Blank.blank? {}
** (Protocol.UndefinedError) protocol Blank not implemented for {}
OTHER TIPS
I know what's my confusing. I also get started with example this site. Firstly my blank.ex is
defprotocol Blank do
def blank?(data)
end
defimpl Blank, for: Integer do
def blank?(_), do: false
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
and after I compile it elixirc blank.ex
, it will create these beam files:
Elixir.Blank.Integer.beam Elixir.Blank.List.beam Elixir.Blank.beam
and secondly my blank.ex is
defprotocol Blank do
@fallback_to_any true
def blank?(data)
end
defimpl Blank, for: Any do
def blank?(_), do: true
end
and I compile it again, I got these beam files:
Elixir.Blank.Any.beam Elixir.Blank.Integer.beam Elixir.Blank.List.beam Elixir.Blank.beam
It doesn't delete the Elixir.Blank.Integer.beam Elixir.Blank.List.beam
files, and when I run in iex:
iex(18)> Blank.blank? [] # it uses Elixir.Blank.List.beam
true
iex(19)> Blank.blank? [6] # it uses Elixir.Blank.List.beam
false
iex(20)> Blank.blank? '12' # it uses Elixir.Blank.List.beam
false
iex(22)> Blank.blank? "' " # it uses Elixir.Blank.Any.beam
true
iex(23)> Blank.blank? "elixi" # it uses Elixir.Any.List.beam
true
iex(24)> Blank.blank? {1} # it uses Elixir.Blank.Any.beam
true
iex(25)> Blank.blank? {1, 2} # it uses Elixir.Blank.Any.beam
true
iex(26)> Blank.blank? 2 # it uses Elixir.Blank.Integer.beam
false
So this is just because my missing of deleting the older beam files manually.