Erlang basics · Lesson 18 (open contents)
01 · Open erl02 · Meet common terms03 · Tell two kinds of text apart04 · Bind a variable once05 · Split and filter a list06 · Parse a number safely07 · Choose one path with case08 · Let a function keep going09 · Put code in a module10 · Compare terms and Boolean results11 · Read and update nested maps12 · Build and inspect UTF-8 binaries13 · Let clauses choose the function path14 · Solve a list twice15 · Choose with patterns, guards, and errors16 · Describe a module and one record17 · Put one tested module in Rebar318 · Return success or failure as data19 · Read and write one file safely20 · Build a data pipeline with functions21 · Keep records behind a module boundary22 · Define a module contract23 · Describe the data contract24 · Test small rules and whole flows25 · Shape builds and make a command26 · Write the project promise27 · Parse one real line28 · Keep the public API small29 · Make the promise executable30 · Package the edge and leave clues31 · Prove the project is done
ERLANG · INTERMEDIATE · LESSON 1825 minutes

Return success or failure as data

Use tagged tuples so callers can handle every expected result.

01 · Start with the whole example

Run this first

Run it once, change one input, and compare the new result.

Erlang
%% Make both outcomes easy to match
ParseAge = fun(Text) ->
  case string:to_integer(Text) of
    {Age, []} when Age >= 0 -> {ok, Age};
    _ -> {error, invalid_age}
  end
end,
{ParseAge("12"), ParseAge("old")}.
Check the result first
  • The result is {{ok,12},{error,invalid_age}}.
02 · Take the code apart

Read from the first line down

  1. Read {ok, Value}: Return a successful value.
  2. Read {error, Reason}: Return an expected failure reason.
  3. Read case ... of: Handle every result tag explicitly.
03 · Meet the new symbols

Symbols are not secret signs

{ok, Value}

Return a successful value.

{error, Reason}

Return an expected failure reason.

case ... of

Handle every result tag explicitly.

04 · Ideas inside the code

Match each name to its meaning

01

tagged result

A tuple beginning with ok or error makes the outcome visible to callers.

02

total function

A total function returns a documented result for every allowed input shape.

03

exception boundary

Reserve exceptions for unexpected failures; return ordinary validation errors as data.

05 · Make the idea clear

Why these forms are useful

Run the example first. Predict one result, then change one input and run it again.

A tuple beginning with ok or error makes the outcome visible to callers.

A total function returns a documented result for every allowed input shape.

DESIGN DECISION

Why this shape?

Why return {:ok, value} or {ok, Value} so often?

Choice

Expected failure stays visible as ordinary data. A caller can list success, known failure, and fallback branches with patterns.

Cost and boundary

Unexpected failures that cannot be handled here may still raise and reach a supervision boundary. Turning every exception into a generic error discards evidence.

A FAMILIAR POINT OF VIEW

Coming from Java, Python, or JavaScript

Java

Familiar starting point
Checked or unchecked exceptions, plus Optional.
What BEAM changes
Tagged results keep expected business outcomes in normal control flow.
False friend
Not every error should crash, and not every exception should be caught here.

Python

Familiar starting point
Exceptions and None.
What BEAM changes
A tag names the failure class instead of asking one empty value to carry every meaning.
False friend
Translate third-party exceptions into a stable result at a boundary.

JavaScript

Familiar starting point
throw, rejected Promises, or null.
What BEAM changes
A tuple is not a Promise. It is data that has already arrived.
False friend
Read contract as acceptance criteria, not an asynchronous Promise.
06 · Change it yourself

Close the answer and try

Reject ages above 120.

Practice starting point
{Age, []} when Age >= 0, Age =< ____ -> {ok, Age};

Target result: Use 120 as the upper boundary.

Stuck? Read one hint

Add the number after =<.

After you run it, see one answer
One answer
{Age, []} when Age >= 0, Age =< 120 -> {ok, Age};
Think about it: Should invalid user input crash the caller?

Usually no. Return a tagged error that the caller can display or recover from.

Take with you

Remember these three lines

  1. 1

    Make outcomes visible in tuples.

  2. 2

    Match every public result tag.

  3. 3

    Use exceptions for genuinely unexpected failures.

Lesson completeRun the code once, then mark this lesson as done.