Skip to content

Instantly share code, notes, and snippets.

@karlseguin
Created February 25, 2020 03:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save karlseguin/21968e20fc5e93cc7db55171b3fcc243 to your computer and use it in GitHub Desktop.
Save karlseguin/21968e20fc5e93cc7db55171b3fcc243 to your computer and use it in GitHub Desktop.
elixir needs a return statement

This works most of the time

def handle(data) do
	with {:ok, product} <- Jason.decode!(data),
	     {:ok, category} <- Category.load(data.category_id)
	do
		# todo
	end
end

But what if you want to have more context sensitive errors. The with's else probably doesn't have the context about which clause failed. So you need to add the context. For simple cases, you can make the code less readable with something like:

def handle(data) do
	with {_, {:ok, product}} <- {:decode, Jason.decode!(data)},
	     {_, {:ok, category}} <- {:category, Category.load(data.category_id)}
	do
		# todo
	else
		{:decode, err} -> # handle decode error
		{:category, err} -> # handle decode error
	end
end

But of course, this is 1) ugly and in the {:category, err} error handler, you don't have access to product, which you might want.

The "cleaner" solution is to have your own wraping functions

def handle(data) do
	with {:ok, product} <- decode(data),
	     {:ok, category} <- load_category(product)
	do
		# todo
	end
end

But then you lose the readability that inlining provides (for such simple statements) and end up with something akin to Go's 200% error handling verbosity tax.

To me, the right solution is mix of a pattern matching + guard clause + return (like in Rust):

product = case Jason.decode(data) do
  {:ok, product} -> product
  err -> 
  	# whatever you need
  	return
end

category = case Category.load(product.category_id) do
  {:ok, category} -> category
  err -> 
  	# whatever you need
  	return
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment