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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mruoss" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mruoss/120/34561_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mruoss
                      <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 it looks like the compiler is able to optimize better if facts are known at compile time.</p>
<p>But here’s something interesting: I have adapted the code a bit because eventually, I’m gonna be working with strings. And if we add binary pattern matching to the mix, performance seems to be different.</p>
<aside class="quote no-group" data-username="LostKobrakai" data-post="5" data-topic="59900">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p><code>in/2</code> doesn’t compile to an <code>Enum.member?/2</code> call when used in a guard:</p>
</blockquote>
</aside>
<p>Side note: Reading the documentation of <code>Kernel.in/2</code> I read the following:</p>
<blockquote>
<p>However, this construct will be inefficient for large lists. In such cases, it is best to stop using guards and use a more appropriate data structure, such as <a href="https://hexdocs.pm/elixir/MapSet.html" rel="noopener nofollow ugc"><code>MapSet</code></a>.</p>
</blockquote>
<p>I therefore added a test using MapSets (which, afaict, is equivalent to <a class="mention" href="/u/al2o3cr" rel="nofollow">@al2o3cr</a>’s test using <code>is_map_key</code>).</p>
<h1><a name="p-308894-tldr-1" class="anchor" href="#p-308894-tldr-1" aria-label="Heading link" rel="nofollow"></a>TLDR;</h1>
<p>In this case, <strong>guards</strong> seem to make the race, being twice as fast as generated functions and 2.5x faster than MapSets</p>
<h1><a name="p-308894-test-2" class="anchor" href="#p-308894-test-2" aria-label="Heading link" rel="nofollow"></a>Test</h1>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Test do
  @chars Range.to_list(1000..1)
  @chars_map_set MapSet.new(1000..1)

  def work(input, fun) do
    Enum.map(input, fun)
  end

  for char &lt;- @chars do
    def do_work_generated(&lt;&lt;unquote(char)::utf8&gt;&gt;), do: unquote(char)

    def do_work_generated(&lt;&lt;unquote(char)::utf8, rest::binary&gt;&gt;) do
      do_work_generated(rest)
    end
  end

  def do_work_guards(&lt;&lt;char::utf8&gt;&gt;) when char in @chars, do: char

  def do_work_guards(&lt;&lt;char::utf8, rest::binary&gt;&gt;) when char in @chars do
    do_work_guards(rest)
  end

  def do_work_mapset(&lt;&lt;char::utf8&gt;&gt;) do
    if MapSet.member?(@chars_map_set, char) do
      char
    else
      :error
    end
  end

  def do_work_mapset(&lt;&lt;char::utf8, rest::binary&gt;&gt;) do
    if MapSet.member?(@chars_map_set, char) do
      do_work_mapset(rest)
    else
      :error
    end
  end
end

Mix.install([:benchee, :benchee_markdown])

list_of_random_strings = fn -&gt;
  Enum.map(1..500_000, fn _ -&gt;
    for _ &lt;- 1..10,
        into: "",
        do: &lt;&lt;Enum.random(Range.to_list(?0..?9) ++ Range.to_list(?A..?z))&gt;&gt;
  end)
end

inputs =
  list_of_random_strings
  |&gt; Stream.repeatedly()
  |&gt; Stream.take(5)
  |&gt; Stream.with_index()
  |&gt; Stream.map(fn {strings, idx} -&gt; {"Batch #{idx + 1}", strings} end)

Benchee.run(
  %{
    "Generated Functions" =&gt; fn input -&gt; Test.work(input, &amp;Test.do_work_generated/1) end,
    "Guards" =&gt; fn input -&gt; Test.work(input, &amp;Test.do_work_guards/1) end,
    "MapSet" =&gt; fn input -&gt; Test.work(input, &amp;Test.do_work_mapset/1) end
  },
  memory_time: 60,
  inputs: inputs,
  parallel: 10,
  formatters: [
    {Benchee.Formatters.Markdown, file: "BENCHMARK_STRINGS.md"},
    Benchee.Formatters.Console
  ]
)
</code></pre>
<h1><a name="p-308894-output-3" class="anchor" href="#p-308894-output-3" aria-label="Heading link" rel="nofollow"></a>Output</h1>
<h2><a name="p-308894-statistics-4" class="anchor" href="#p-308894-statistics-4" aria-label="Heading link" rel="nofollow"></a>Statistics</h2>
<h2><a name="p-308894-statistics-5" class="anchor" href="#p-308894-statistics-5" aria-label="Heading link" rel="nofollow"></a>Statistics</h2>
<p><strong>Input: Batch 1</strong></p>
<p>Run Time</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Average</th>
    <th>Devitation</th>
    <th>Median</th>
    <th>99th&nbsp;%</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>31.07</td>
    <td>32.19 ms</td>
    <td>±8.67%</td>
    <td>32.09 ms</td>
    <td>46.84 ms</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.54</td>
    <td>64.36 ms</td>
    <td>±5.44%</td>
    <td>63.96 ms</td>
    <td>90.67 ms</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>10.99</td>
    <td>91.02 ms</td>
    <td>±5.33%</td>
    <td>90.73 ms</td>
    <td>123.52 ms</td>
  </tr>
</tbody></table>
<p>Run Time Comparison</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Slower</th>
  </tr><tr>
    <td>Guards</td>
    <td>31.07</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.54</td>
    <td>2.0x</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>10.99</td>
    <td>2.83x</td>
  </tr>
</tbody></table>
<p>Memory Usage</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>Average</th>
    <th>Factor</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>26.70 MB</td>
    <td>&nbsp;</td>
  </tr>
    <tr>
    <td>Generated Functions</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
    <tr>
    <td>MapSet</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
</tbody></table>
<p><strong>Input: Batch 2</strong></p>
<p>Run Time</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Average</th>
    <th>Devitation</th>
    <th>Median</th>
    <th>99th&nbsp;%</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>31.57</td>
    <td>31.68 ms</td>
    <td>±8.91%</td>
    <td>31.97 ms</td>
    <td>45.93 ms</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.64</td>
    <td>63.94 ms</td>
    <td>±5.55%</td>
    <td>64.00 ms</td>
    <td>91.14 ms</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>11.10</td>
    <td>90.06 ms</td>
    <td>±4.90%</td>
    <td>90.00 ms</td>
    <td>119.82 ms</td>
  </tr>
</tbody></table>
<p>Run Time Comparison</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Slower</th>
  </tr><tr>
    <td>Guards</td>
    <td>31.57</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.64</td>
    <td>2.02x</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>11.10</td>
    <td>2.84x</td>
  </tr>
</tbody></table>
<p>Memory Usage</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>Average</th>
    <th>Factor</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>26.70 MB</td>
    <td>&nbsp;</td>
  </tr>
    <tr>
    <td>Generated Functions</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
    <tr>
    <td>MapSet</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
</tbody></table>
<p><strong>Input: Batch 3</strong></p>
<p>Run Time</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Average</th>
    <th>Devitation</th>
    <th>Median</th>
    <th>99th&nbsp;%</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>31.43</td>
    <td>31.81 ms</td>
    <td>±8.78%</td>
    <td>31.89 ms</td>
    <td>46.68 ms</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.40</td>
    <td>64.95 ms</td>
    <td>±5.93%</td>
    <td>64.84 ms</td>
    <td>93.51 ms</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>11.04</td>
    <td>90.54 ms</td>
    <td>±4.83%</td>
    <td>90.49 ms</td>
    <td>118.91 ms</td>
  </tr>
</tbody></table>
<p>Run Time Comparison</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Slower</th>
  </tr><tr>
    <td>Guards</td>
    <td>31.43</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.40</td>
    <td>2.04x</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>11.04</td>
    <td>2.85x</td>
  </tr>
</tbody></table>
<p>Memory Usage</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>Average</th>
    <th>Factor</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>26.70 MB</td>
    <td>&nbsp;</td>
  </tr>
    <tr>
    <td>Generated Functions</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
    <tr>
    <td>MapSet</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
</tbody></table>
<p><strong>Input: Batch 4</strong></p>
<p>Run Time</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Average</th>
    <th>Devitation</th>
    <th>Median</th>
    <th>99th&nbsp;%</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>31.08</td>
    <td>32.18 ms</td>
    <td>±8.48%</td>
    <td>32.34 ms</td>
    <td>46.62 ms</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.25</td>
    <td>65.58 ms</td>
    <td>±6.42%</td>
    <td>65.17 ms</td>
    <td>97.31 ms</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>12.31</td>
    <td>81.22 ms</td>
    <td>±7.78%</td>
    <td>79.51 ms</td>
    <td>108.75 ms</td>
  </tr>
</tbody></table>
<p>Run Time Comparison</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Slower</th>
  </tr><tr>
    <td>Guards</td>
    <td>31.08</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.25</td>
    <td>2.04x</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>12.31</td>
    <td>2.52x</td>
  </tr>
</tbody></table>
<p>Memory Usage</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>Average</th>
    <th>Factor</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>26.70 MB</td>
    <td>&nbsp;</td>
  </tr>
    <tr>
    <td>Generated Functions</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
    <tr>
    <td>MapSet</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
</tbody></table>
<p><strong>Input: Batch 5</strong></p>
<p>Run Time</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Average</th>
    <th>Devitation</th>
    <th>Median</th>
    <th>99th&nbsp;%</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>29.61</td>
    <td>33.78 ms</td>
    <td>±8.29%</td>
    <td>33.12 ms</td>
    <td>50.84 ms</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.13</td>
    <td>66.08 ms</td>
    <td>±5.99%</td>
    <td>65.88 ms</td>
    <td>97.77 ms</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>11.20</td>
    <td>89.32 ms</td>
    <td>±53.75%</td>
    <td>82.30 ms</td>
    <td>440.40 ms</td>
  </tr>
</tbody></table>
<p>Run Time Comparison</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>IPS</th>
    <th>Slower</th>
  </tr><tr>
    <td>Guards</td>
    <td>29.61</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <td>Generated Functions</td>
    <td>15.13</td>
    <td>1.96x</td>
  </tr>
  <tr>
    <td>MapSet</td>
    <td>11.20</td>
    <td>2.64x</td>
  </tr>
</tbody></table>
<p>Memory Usage</p>
<table>
  <tbody><tr>
    <th>Name</th>
    <th>Average</th>
    <th>Factor</th>
  </tr>
  <tr>
    <td>Guards</td>
    <td>26.70 MB</td>
    <td>&nbsp;</td>
  </tr>
    <tr>
    <td>Generated Functions</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
    <tr>
    <td>MapSet</td>
    <td>26.70 MB</td>
    <td>1.0x</td>
  </tr>
</tbody></table> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="308894" 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/guards-vs-generated-functions-which-is-faster-more-performant/59900/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-308894" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="308894"
                     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 #11"></div>
  </section>
</div>
    <div class="postbit" id="308965" data-post-id="308965">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="hst337" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  hst337
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>This exact test case has nothing to do for “guards vs generated functions”</p>
<p><code>when x in 1..100</code> gets compiled into <code>when x &gt; 1 and x &lt; 100</code>, so it is just faster.</p>
<p>So, to answer the original question “Performance Question: guards vs. generated functions: which is faster?”: none is faster, both are a different tools used for different tasks. The task you’ve brought up in the original post is made up and is actually solved not by <code>x in y</code> guard or generated clauses, but just by <code>x &gt;= left and x &lt;= right</code></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="308965" 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/guards-vs-generated-functions-which-is-faster-more-performant/59900/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-308965" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="308965"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>