# Metaprogramming Elixir: code example error (page 22)

**URL:** <https://forum.devtalk.com/t/metaprogramming-elixir-code-example-error-page-22/67298>\
**Category:** PragProg Customers\
**Tags:** book-metaprogramming-elixir, errata\
**Created:** [3 August 2022 14:14 UTC](https://forum.devtalk.com/t/metaprogramming-elixir-code-example-error-page-22/67298 "2022-08-03T14:14:05Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![deadbeef](https://forum.devtalk.com/letter_avatar_proxy/v4/letter/d/8491ac/32.png) [@deadbeef](https://forum.devtalk.com/u/deadbeef)\
**Post date:** [3 August 2022 14:14 UTC](https://forum.devtalk.com/t/metaprogramming-elixir-code-example-error-page-22/67298/1 "2022-08-03T14:14:05Z")

</div>

The code example on page 22 is intended to show how to re-create Elixir’s `if` macro. However, it _uses_ `if` on line 3.

The macro block just passes the args to `if`. This could be a typo and meant to be `my_if`. If that’s the case, a simple substitution would result in the error `... cannot invoke macro my_if/2 before its definition`.

```auto
defmacro my_if(expr, do: if_block), do: if(expr, do: if_block, else: nil)
                                        ^^

```

That leads me to believe the example can be re-written to be more similar to Elixir’s own implementation[^1](https://github.com/elixir-lang/elixir/blob/f8f7b4f23e1a3932295b0fc0655d96bafd772b2c/lib/elixir/lib/kernel.ex#L3710-L3732), e.g.

```auto
defmodule ControlFlow do
  defmacro my_if(expr, clauses) do
    build_my_if(expr, clauses)
  end

  defp build_my_if(expr, do: if_block) do
    build_my_if(expr, do: if_block, else: nil)
  end

  defp build_my_if(expr, do: if_block, else: else_block) do
    quote do
      case unquote(expr) do
        result when result in [false, nil] -> unquote(else_block)
        _ -> unquote(if_block)
      end
    end 
  end
end

```

Same idea, but instead of 2 macros we have 1 macro that passes to a private function with 2 clauses.

Further, using the built-in `if` leads to an unexpected expansion, using the example:

```auto
iex> quote do ControlFlow.my_if 1 == 1, do: :ok end |> Macro.expand_once( __ENV__ )
:ok

```

I believe this is because Elixir’s implementation further reduces tautologies[^2](https://github.com/elixir-lang/elixir/blob/f8f7b4f23e1a3932295b0fc0655d96bafd772b2c/lib/elixir/lib/kernel.ex#L3719), which the example doesn’t. From the example, we’d expect to see `:case` in the resulting AST (this confusion is what lead me here originally).
