It "just works" in Go too, minus immutability, but congrats on your technology decision. You don't get type checking but c'est la vie.
-module(someone_was_wrong_on_the_internet).
-export([init/0, fizzbuzzer/1]).
-spec init() -> list(pos_integer() | binary()).
init() ->
List = [-1, 0, 0.1, 1, 2, 3, 5, 15, 2, 3, 5, 15, 1],
[fizzbuzzer(Result) || Result <- List].
-spec fizzbuzzer(pos_integer()) -> pos_integer() | binary().
fizzbuzzer(Number) when Number rem 15 =:= 0 ->
<<"FizzBuzz">>;
fizzbuzzer(Number) when Number rem 5 =:= 0 ->
<<"Buzz">>;
fizzbuzzer(Number) when Number rem 3 =:= 0 ->
<<"Fizz">>;
fizzbuzzer(Number) ->
Number.
Dialyzer will fail the type check until you remove [-1, 0, 0.1] from the list. Not with a particularly helpful error, but it does fail it nonetheless.The code itself is a valid program that runs, but it produces incorrect output, because 0 rem 15 =:= 0, so you get <<"FizzBuzz">> where you'd expect to get a 0 in the list. By running Dialyzer in my build chain I can catch that my implementation doesn't match my constraints at compile-time. In a way that I otherwise would have only found at runtime.
Though while creating this little pointless example one thing I'm not super clear on is why Dialyzer fails to notice that my return type from
fizzbuzzer(Number) ->
Number.
if I change it to fizzbuzzer(Number) ->
-Number.
will return a neg_integer() and fail to satisfy the return spec. Despite that I've told it the input must be a be a pos_integer(). Unless I enable the -Wspecdiffs flag, in which case it notices the problem.I choose wording carefully for a reason