trashyEx

trashyEx

Hello,

Probably related with macros (since I am learning them bit a bit), but let’s see if I can get some insight in what is going on.

I installed the decorator library (Elixir function decorators — decorator v1.4.0). Then, using a hello-world Phoenix project, I have a generic print decorator, but I would like to have a specific one for %Plug.Conn{}, and it does not work.

PageController:

  @decorate print_conn()
  def index_specific(%Plug.Conn{} = conn, _params) do
    IO.inspect(conn)
    render(conn, "index.html")
  end

  @decorate print()
  def index_generic(conn, _params) do
    IO.inspect(conn)
    render(conn, "index.html")
  end

The decorators from HwDecorator:

defmodule HwDecorator do
  use Decorator.Define, [print: 0, print_conn: 0]

  # at compile-time it does not know if is Plug.Conn
  # def print(body, %{args: [%Plug.Conn{} = conn, _params]} = context) do
  # so I assume we can work only with arity/2
  # alternative, to mark with print_conn
  def print(body, %{args: [conn, _params]} = context) do
    quote do
      IO.puts("Func Conn begin: #{Atom.to_string(unquote(context.name))}")
      unquote(body)
      IO.puts("Func Conn end: #{Atom.to_string(unquote(context.name))}")
    end
  end

  def print(body, context) do
    x = 3
    quote do
      #  IO.inspect(unquote(context), label: "context")  <---- WHY:2
      IO.puts("Func begin: #{unquote(x)} #{Atom.to_string(unquote(context.name))}")
      unquote(body)
      IO.puts("Func end: #{Atom.to_string(unquote(context.name))}")
    end
  end

  # This does not work:
  #  def print_conn(body, %{args: [%Plug.Conn{} = conn, _params]} = context) do. # WHY:1
  def print_conn(body, %{args: [conn, _params]} = context) do
    quote do
      IO.puts("Func Conn type begin: #{Atom.to_string(unquote(context.name))}")
      unquote(body)
      IO.puts("Func Conn type end: #{Atom.to_string(unquote(context.name))}")
    end
  end
end

The function receives:

  [{:=, [line: 8], [
      {:%, [line: 8], [
        {:__aliases__, [line: 8], [:Plug, :Conn]}, {:%{}, [line: 8], []}
      ]},
      {:conn, [line: 8], nil}
    ]},
    {:_params, [line: 8], nil}
  ]

So, I assume it is not matching since %Plug.Conn{} = conn is not the same as all those tuples from above.

I have 2 questions.

  • WHY:1: What can be done to achieve using types in the decorator functions? Like, for instance, matching Plug.Conn with the first param? I annotate the type in index_specific in case it helps, since I imagine index_generic does not know it is Plug.Conn at compile time (where I suspect the macros/decorators are being executed).
== Compilation error in file lib/hw_phoenix_web/controllers/page_controller.ex ==
** (FunctionClauseError) no function clause matching in HwDecorator.print_conn/2

    The following arguments were given to HwDecorator.print_conn/2:

        # 1
        {:__block__, [], [{{:., [line: 9], [{:__aliases__, [line: 9], [:IO]}, :inspect]}, [line: 9], [{:conn, [line: 9], nil}]}, {:render, [line: 10], [{:conn, [line: 10], nil}, "index.html"]}]}

        # 2
        %Decorator.Decorate.Context{args: [{:=, [line: 8], [{:%, [line: 8], [{:__aliases__, [line: 8], [:Plug, :Conn]}, {:%{}, [line: 8], []}]}, {:conn, [line: 8], nil}]}, {:_params, [line: 8], nil}], arity: 2, module: HwPhoenixWeb.PageController, name: :index}

    lib/hw_phoenix/decorator.ex:28: HwDecorator.print_conn/2
    (decorator 1.4.0) lib/decorator/decorate.ex:164: Decorator.Decorate.apply_decorator/3
    (elixir 1.13.4) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
    (decorator 1.4.0) lib/decorator/decorate.ex:128: Decorator.Decorate.decorate/4
    (elixir 1.13.4) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
    (decorator 1.4.0) expanding macro: Decorator.Decorate.before_compile/1
    lib/hw_phoenix_web/controllers/page_controller.ex:1: HwPhoenixWeb.PageController (module)
  • WHY:2: Why the context variable cannot be used directly there? It is just an struct. I don’t understand why context.args or context.name work, but not context.
== Compilation error in file lib/hw_phoenix_web/controllers/page_controller.ex ==
** (CompileError) lib/hw_phoenix_web/controllers/page_controller.ex: invalid quoted expression: %Decorator.Decorate.Context{args: [{:conn, [line: 14], nil}, {:_params, [line: 14], nil}], arity: 2, module: HwPhoenixWeb.PageController, name: :index_two}

Please make sure your quoted expressions are made of valid AST nodes. If you would like to introduce a value into the AST, such as a four-element tuple or a map, make sure to call Macro.escape/1 before

Showing Posts 1 to 2

trashyEx

trashyEx OP

Any idea?

al2o3cr

al2o3cr

%Plug.Conn{} = conn is in fact exactly those tuples at compile-time:

iex(1)> quote do
...(1)> %Plug.Conn{} = conn
...(1)> end

{:=, [],
 [
   {:%, [], [{:__aliases__, [alias: false], [:Plug, :Conn]}, {:%{}, [], []}]},
   {:conn, [], Elixir}
 ]}

Check out the very final example from the decorator docs - inside the body of the decorator, context.args has the a list of ASTs from the function’s head so the values can only be used inside of a quote with unquote.

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
mnkhod
So i have been using ash framework for a while and i love it. However currently the issue im having with ash framework is the error handl...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews