Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API change suggestion - Descriptive keywords instead of do blocks #4

Open
tmbb opened this issue Jun 21, 2017 · 0 comments
Open

API change suggestion - Descriptive keywords instead of do blocks #4

tmbb opened this issue Jun 21, 2017 · 0 comments

Comments

@tmbb
Copy link

tmbb commented Jun 21, 2017

Currently, Jeeves uses do blocks after update_state.
This is flexible, as it allows you to use multiple statements after updating the state.
The README gives some examples.

Using the "full" do block:

defmodule Fib do
  # ...
  def fib(n) do
    case cache[n] do
    nil ->
      fib_n = fib(n-2, cache) + fib(n-1, cache)
      update_state(Map.put(cache, n, fib_n)) do
        fib_n
        end
    cached_result ->
      cached_result      
    end 
  end
end

Using the "abbreviated" do block:

defmodule FibCache do
  # ...
  def put(n, fib_n) do
    state
    |> Map.put(n, fib_n)
    |> update_state(do: fib_n)
  end
end

This doesn't read very well to me, and it's not clear at a first glance what is a state update and what is a return value. However, if you really want to have multiple statements after updating the state, then maybe there are no alternatives.

But how often does one want multiple statements in practice?
If we don't need multiple statements, then we can drop the block and use a more descriptive keyword, like :returning.

This would give use more "user-friendly" versions:

defmodule Fib do
  # ...
  def fib(n) do
    case cache[n] do
    nil ->
      fib_n = fib(n-2, cache) + fib(n-1, cache)
      # Changed line:
      update_state Map.put(cache, n, fib_n), returning: fib_n
    cached_result ->
      cached_result      
    end 
  end
end
defmodule FibCache do
  # ...
  def put(n, fib_n) do
    state
    |> Map.put(n, fib_n)
    # Changed line:
    |> update_state(returning: fib_n)
  end
end

Note that now only the keyword form is supported, and everything is made uniform.

An alternative approach would be to flip things around and have a macro (or function, depending on the way Jeeves is implemented) like return that takes a value to return and a :with_new_state keyword that allows you to write:

defmodule Fib do
  # ...
  def fib(n) do
    case cache[n] do
    nil ->
      fib_n = fib(n-2, cache) + fib(n-1, cache)
      return fib_n,  with_new_state: Map.put(cache, n, fib_n)
    cached_result ->
      cached_result      
    end 
  end
end

Unlike the update_state form, in which the new state is fundamental and the return value feels like an afterthought, in the return form, the return value is fundamental and the new state is the afterthought.
I prefer the update_state form, but that's very subjective.

These are mostly cosmetic changes to the API, and maybe they are a little irrelevant, but in my opinion they might enhance readability. Losing the ability to use do blocks doesn't feel like a big deal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant