13
\$\begingroup\$

So I was playing with writing FizzBuzz in Elixir; this is my first, naive implementation:

defmodule FizzBuzz do
  def getFB(n) do
    cond do
      rem(n,15) == 0 -> 
        IO.puts "FizzBuzz"
      rem(n,3) == 0 -> 
        IO.puts "Fizz"
      rem(n,5) == 0 -> 
        IO.puts "Buzz"
      true -> 
        IO.puts "#{n}"
    end
  end
end

So then I thought to myself--this is Elixir! I should be able to spawn a secondary process for my FizzBuzz needs. So after a bit of hacking I got this:

defmodule FizzBuzz do
  @fizz_buzz 15
  @fizz 3
  @buzz 5
  @default_timeout 60_000

  def getFB() do
    receive do  
      {pid,n} when rem(n,@fizz_buzz) == 0 -> 
        send pid,"FizzBuzz"
      {pid,n} when rem(n,@fizz) == 0 -> 
        send pid,"Fizz"
      {pid,n} when rem(n,@buzz) == 0 -> 
        send pid,"Buzz"
      {pid,n} -> 
        send pid,"#{n}"
    after 
      @default_timeout -> raise "Timed out"
    end
    getFB() #Keep the process alive
  end
end

and I would use it like so:

fbPid = spawn &FizzBuzz.getFB/0

send fbPid,{self(),15}
receive do
   r -> IO.puts(r)
after
  1000 -> raise "Timed out"
end

I realize this is a small/simple example but I'd still love to hear the thoughts of other experienced Elixir devs. Where can I make this better?

\$\endgroup\$
9
\$\begingroup\$

The use-case you came up with looks like a very clear candidate to be a GenServer.

A GenServer implementation will eliminate your need to manage the serving process, and using its client-side API conventions will also simplify the client usage.

Here is a sample implementation of a fizzbuzz:

defmodule FizzBuzz do
    use GenServer

    @fizz_buzz 15
    @fizz 3
    @buzz 5

    def start_link(default) do
      GenServer.start_link(__MODULE__, default, name: __MODULE__)
    end

    # Client API

    def getFB(n) do
        GenServer.call(__MODULE__, {:fb, n})
    end

    # Server API

    def handle_call({:fb, n}, _from, state) when rem(n, @fizz_buzz) == 0 do
        {:reply, "FizzBuzz", state}
    end

    def handle_call({:fb, n}, _from, state) when rem(n, @fizz) == 0 do
        {:reply, "Fizz", state}
    end

    def handle_call({:fb, n}, _from, state) when rem(n, @buzz) == 0 do
        {:reply, "Buzz", state}
    end

    def handle_call({:fb, n}, _from, state) do
        {:reply, "#{n}", state}
    end

end

Its usage would be:

FizzBuzz.start_link([])

IO.puts FizzBuzz.getFB(15)
# FizzBuzz
\$\endgroup\$
  • \$\begingroup\$ That's good stuff as the genserver (and analogous OTP constructs) seem to be at the heart of Erlang/Elixir's raison d'etre. \$\endgroup\$ – Onorio Catenacci Aug 14 '14 at 12:46
  • 1
    \$\begingroup\$ Sorry @UriAgassi--I just now noticed that I had never marked your answer as the accepted one. I just fixed that. \$\endgroup\$ – Onorio Catenacci Oct 9 '15 at 12:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.