Are there ways enforcing a module to implement protocols ?
I’m using behaviour to check implementing functions now. It seems like:
defmodule Vehicle do
@callback name() :: String.t()
end
defmodule Car do
@behaviour Vehicle
defstruct details: ""
@impl true
def name(), do: "Car"
defimpl String.Chars do
def to_string(%{details: details}), do: "introduction #{details} outroduction"
end
end
When name() does not defined in Car
module, the compiler warns it.
But if String.Chars.to_string()
is missing, no warnings are produced.
I think it’s good to be able to warn not implemented protocols. How can you do that?
No warning is produced because it’s not a mandatory protocol to implement so I don’t see why the compiler would warn you about it.
Then, my question is if there is a way enforcing the module to always implement protocol like behaviour.
For example, can I define protocol implementation as callback? like:
defmodule Vehicle do
@callback String.Chars.to_string(t) :: String.t()
end
(This produced invalid type specification error.)
It’s doable if you write a __using__
macro that encapsulates the @behaviour (like use GenServer
does) that also has an @after_compile hook that manually checks for the existence of the defimpl. You might not want to bother, though.
Using macro was an idea, and @after_compile is interesting, I did not think about it. But I feel these are too much as you say.
Thank you!
yeah, elixir just isn’t rigourously a statically-typed language. I do think it’s neat that Elixir lets you drop in static-ish things in if you don’t mind putting in a little bit of effort. (I think it’s worth making highly critical things statically checked)… Of late, I’m doing a lot of static typechecking by putting my deploy configs in as verified, compile-time artifacts, which prevents me from attempting to deploy stupid things, and it’s been great.