The defimpl macro lets you give Elixir the implementation of a protocol for one or more types. The code that follows is the implementation of the Inspect protocol for PIDs and references.
| defimpl Inspect, for: PID do |
| def inspect(pid, _opts) do |
| "#PID" <> IO.iodata_to_binary(pid_to_list(pid)) |
| end |
| end |
| |
| defimpl Inspect, for: Reference do |
| def inspect(ref, _opts) do |
| '#Ref' ++ rest = :erlang.ref_to_list(ref) |
| "#Reference" <> IO.iodata_to_binary(rest) |
| end |
| end |
Finally, the Kernel module implements inspect, which calls Inspect.inspect with its parameter. This means that when you call inspect(self), it becomes a call to Inspect.inspect(self). And because self is a PID, this in turn resolves to something like "#PID<0.25.0>".
Behind the scenes, defimpl puts the implementation for each protocol-and-type combination into a separate module. The protocol for Inspect for the PID type is in the module Inspect.PID. And because you can recompile modules, you can change the implementation of functions accessed via protocols.
| iex> inspect self |
| "#PID<0.25.0>" |
| iex> defimpl Inspect, for: PID do |
| ...> def inspect(pid, _) do |
| ...> "#Process: " <> IO.iodata_to_binary(:erlang.pid_to_list(pid)) <> "!!" |
| ...> end |
| ...> end |
| iex:3: redefining module Inspect.PID |
| {:module, Inspect.PID, <<70,79.... |
| iex> inspect self |
| "#Process: <0.25.0>!!" |