Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EarlyReturn

Early return support for Elixir functions.

Installation

Add early_return to your list of dependencies in mix.exs:

def deps do
  [
    {:early_return, "~> 1.0.0"}
  ]
end

Usage

Add use EarlyReturn to any module to enable the return macro:

defmodule MyModule do
  use EarlyReturn

  def divide(a, b) do
    if b == 0, do: return {:error, :division_by_zero}

    {:ok, a / b}
  end
end

return with no arguments returns nil:

def maybe_process(data) do
  if invalid?(data), do: return()

  do_work(data)
end

Both def and defp are supported. User-defined catch and rescue blocks are preserved:

def fetch(url) do
  if cached = Cache.get(url), do: return cached

  HTTP.get!(url)
rescue
  e in HTTP.Error -> {:error, e.reason}
end

How it works

use EarlyReturn replaces Kernel.def/2 and Kernel.defp/2 with versions that wrap function bodies in a catch block. The return macro expands to a throw, which is caught by the wrapping catch and returned as the function's result.

Caveats

Non-local return from anonymous functions

return inside a fn will return from the enclosing def, not from the fn itself. This is similar to Ruby's return inside blocks:

def first_even(list) do
  Enum.each(list, fn x ->
    if rem(x, 2) == 0, do: return x  # returns from first_even, not the fn
  end)

  nil
end

No process boundary crossing

throw does not cross process boundaries. Using return inside spawn, Task.async, or similar will crash the child process with {:nocatch, {:early_return, value}}.

Interaction with user-defined try/catch

If you write your own try/catch inside the function body with a catch-all clause, it will intercept the return throw before it reaches the function-level handler:

def example do
  try do
    return :early  # caught by the try below, not by def
  catch
    x -> x  # swallows the return
  end
end

Formatter

To allow return value without parentheses, add :early_return to your formatter's :import_deps:

# .formatter.exs
[
  import_deps: [:early_return],
  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages