HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Multi-process FizzBuzz in Elixir

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
elixirmultiprocessfizzbuzz

Problem

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?

Solution

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

Code Snippets

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
FizzBuzz.start_link([])

IO.puts FizzBuzz.getFB(15)
# FizzBuzz

Context

StackExchange Code Review Q#57034, answer score: 9

Revisions (0)

No revisions yet.