<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="12882" data-post-id="12882">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="vic" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/vic/120/11426_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  vic
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Asdf Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Very nice ! just sent you a couple of PR for your new project. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="12882" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-12882" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="12882"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="12896" data-post-id="12896">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="arjan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/arjan/120/2737_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  arjan
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="12896" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-12896" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="12896"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="12912" data-post-id="12912">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="michalmuskala" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/michalmuskala/120/20288_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  michalmuskala
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I will second <a class="mention" href="/u/benwilson512" rel="nofollow">@benwilson512</a> here - I’m not sure decorator pattern really fits in Elixir.</p>
<p>As to instrumentation - we have the awesome tracing abilities that allow us to introspect function calls without adding any line of code - even in production.</p>
<p>There are native things in <code>:dbg</code> and <code>:trace</code>, but I prefer <code>:recon</code> and recently started using <a href="https://github.com/tatsuya6502/recon_ex" class="inline-onebox" rel="noopener nofollow ugc">GitHub - tatsuya6502/recon_ex: Elixir wrapper for Recon, tools to diagnose Erlang VM safely in production · GitHub</a></p>
<pre><code># Prints next 3 calls to SomeModule.function with return value
ReconTrace.calls({SomeModule, :function, fn _ -&gt; :return end}, 3)
# Prints next 3 calls to SomeModule.function with return value in process pid
ReconTrace.calls({SomeModule, :function, fn _ -&gt; :return end}, 3, pid: pid)
</code></pre>
<p>It’s much more powerful, than this. Those should be good examples of things I use the most.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="12912" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-12912" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="12912"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="21830" data-post-id="21830">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="slashdotdash" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/slashdotdash/120/3090_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  slashdotdash
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Just discovered your decorator library as I was searching for exactly this behaviour. Wrapping method calls with timing traces. Perfect solution for me; thanks for making it available.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="21830" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-21830" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="21830"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="21839" data-post-id="21839">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>This may be too late but you really really really shouldn’t copy Elixir’s private source. When you rely on Elixir internal details and then your code breaks when users of your code update their Elixir version, it gives a sense of instability to the ecosystem while we are working very hard to keep Elixir backwards compatible.</p>
<p>One suggestion is, when you are traversing the AST, you should see if that’s a decorated attribute and, if not, you should regenerate it as <code>Kernel.@(ast)</code> or something similar.</p>
<p>However, you should not need to traverse the AST to implement decorators. It should be possible to implement this by using <code>@on_definition</code>. Since <code>@on_definition</code> is going to be invoked before every function clause, you can collect information such as function body, arguments, etc and then use <code>@before_compile</code> to traverse all of the collected functions, calling the decorator, and emitting new clauses. You can also use <code>defoverridable</code> and tell decorators to simply invoke <code>super</code> when they need to call the parent function.</p>
<p>Here is an example implementation:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Decorator do
  defmacro __using__(_) do
    quote do
      @on_definition Decorator
      @before_compile Decorator
      @decorators %{}
      @decorator nil
    end
  end

  def __on_definition__(env, kind, fun, args, _guards, _body) do
    if decorator = Module.get_attribute(env.module, :decorator) do
      decorators = Module.get_attribute(env.module, :decorators)
      decorators = Map.put(decorators, {kind, fun, length(args)}, decorator)
      Module.put_attribute(env.module, :decorators, decorators)
      Module.put_attribute(env.module, :decorator, nil)
    end
    :ok
  end

  defmacro __before_compile__(env) do
    decorators = Module.get_attribute(env.module, :decorators)
    for {{kind, fun, arity}, decorator} &lt;- decorators do
      args = generate_args(arity)
      body = decorator.decorate(kind, fun, args)
      quote do
        defoverridable [{unquote(fun), unquote(arity)}]

        Kernel.unquote(kind)(unquote(fun)(unquote_splicing(args))) do
          unquote(body)
        end
      end
    end
  end

  defp generate_args(0), do: []
  defp generate_args(n), do: for(i &lt;- 1..n, do: Macro.var(:"var#{i}", __MODULE__))
end

defmodule InspectDecorator do
  def decorate(_kind, _name, args) do
    quote do
      IO.inspect super(unquote_splicing(args))
    end
  end
end

defmodule Sample do
  use Decorator

  @decorator InspectDecorator
  def add(a, b) do
    a + b
  end
end

# Should print 3
Sample.add(1, 2)
</code></pre>
<p>I don’t quite agree with the idea but I believe the implementation above would be better than relying on Elixir internals. The sketch above is also not complete, for example, we don’t support multiple decorators, but you should be able to change it by changing the <code>on_definition</code> implementation.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="21839" data-batch-url="/posts/batch_likers">
                        18
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-21839" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="21839"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="21855" data-post-id="21855">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="arjan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/arjan/120/2737_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  arjan
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks José for your reply. At the time, overriding <code>Kernel.@</code> felt like the only solution, but I’ll revisit this based on your example. Your solution looks elegant – I never knew you could override a function from within the same module.</p>
<p>I’m still wondering how to do multiple decorators without inspecting the module’s AST or doing something with <code>Kernel.@</code> though, because the putting 2 <code>@decorate</code> module attributes below each other just causes the last one to overwrite he previous value iirc.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="21855" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-21855" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="21855"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="21882" data-post-id="21882">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="vic" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/vic/120/11426_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  vic
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Asdf Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="arjan" data-post="27" data-topic="2050">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/arjan/48/2737_2.png" class="avatar"> arjan:</div>
<blockquote>
<p>2 <span class="mention">@decorate</span> module attributes below each other just causes the last one to overwrite he previous value</p>
</blockquote>
</aside>
<p>They wont if you define the attribute like   <code>Module.register_attribute __MODULE__, :decorate, accumulate: true</code>, then it will be a list (latest attr value would be first), and you can just  get this list <code>__on_definition__</code> and reset it to nil for next functions.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="21882" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-21882" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="21882"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="21883" data-post-id="21883">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="arjan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/arjan/120/2737_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  arjan
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Yeah, didt think of that option, should be doable!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="21883" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-21883" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="21883"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="21946" data-post-id="21946">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="slashdotdash" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/slashdotdash/120/3090_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  slashdotdash
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here’s the <a href="https://10consulting.com/2017/01/20/building-product-recommendations-using-elixir-gen-stage-flow/#collect-progress-stats" rel="noopener nofollow ugc">usage of the decorator</a> I implemented.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule ProgressDecorator do
  use Decorator.Define, [progress: 0]

  def progress(body, context) do
    quote do
      reply = unquote(body)

      case reply do
        list when is_list(list) -&gt; Progress.incr(unquote(context.name), length(list))
        _ -&gt; Progress.incr(unquote(context.name), 1)
      end

      reply
    end
  end
end
</code></pre>
<p>It’s used to track progress of the stages in a Flow pipeline to generate a visualisation.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="21946" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-21946" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="21946"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="22167" data-post-id="22167">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="arjan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/arjan/120/2737_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  arjan
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m <a href="https://github.com/arjan/decorator/blob/internals-refactor/lib/decorators/define.ex" rel="noopener nofollow ugc">getting there</a> but there’s one issue with this approach, and that’s when decorating a private function, Elixir raises a warning that <code>defoverridable</code> is deprecated for <code>defp</code>’s. Any suggestion on how to address this?</p>
<p>I guess the easiest way is to stop supporting decorators for <code>defp</code> altogether <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="22167" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nicest-way-to-emulate-function-decorators/2050/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-22167" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="22167"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/2050/load_more?page=4">Load more posts (15 remaining)</a>
</div></template></turbo-stream>