<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">

<chapter>
  <header>
    <copyright>
      <year>2001</year><year>2021</year>
      <holder>Ericsson AB. All Rights Reserved.</holder>
    </copyright>
    <legalnotice>
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
      limitations under the License.
    </legalnotice>

    <title>Common Caveats</title>
    <prepared>Bjorn Gustavsson</prepared>
    <docno></docno>
    <date>2001-08-08</date>
    <rev></rev>
    <file>commoncaveats.xmlsrc</file>
  </header>

  <p>This section lists a few modules and BIFs to watch out for, not only
  from a performance point of view.</p>

  <section>
     <title>Timer Module</title>

     <p>Creating timers using <seemfa
     marker="erts:erlang#send_after/3">erlang:send_after/3</seemfa>
     and
     <seemfa marker="erts:erlang#start_timer/3">erlang:start_timer/3</seemfa>,
     is much more efficient than using the timers provided by the
     <seeerl marker="stdlib:timer">timer</seeerl> module in STDLIB.
     The <c>timer</c> module uses a separate process to manage the timers.
     That process can easily become overloaded if many processes
     create and cancel timers frequently.</p>

     <p>The functions in the <c>timer</c> module that do not manage timers
     (such as <c>timer:tc/3</c> or <c>timer:sleep/1</c>), do not call the
     timer-server process and are therefore harmless.</p>
  </section>

  <section>
    <title>Accidental Copying and Loss of Sharing</title>

    <p>When spawning a new process using a fun, one can accidentally
    copy more data to the process than intended. For example:</p>

    <p><em>DO NOT</em></p>
    <codeinclude file="efficiency_guide.erl" tag="%%acc1" type="erl"/>

    <p>The code in the fun will extract one element from the record
    and print it. The rest of the <c>state</c> record is not used.
    However, when the <c>spawn/1</c> function is executed, the entire
    record is copied to the newly created process.</p>

    <p>The same kind of problem can happen with a map:</p>
    <p><em>DO NOT</em></p>
    <codeinclude file="efficiency_guide.erl" tag="%%acc2" type="erl"/>

    <p>In the following example (part of a module implementing the
    <seeerl marker="stdlib:gen_server">gen_server</seeerl> behavior)
    the created fun is sent to another process:</p>

    <p><em>DO NOT</em></p>
    <codeinclude file="efficiency_guide.erl" tag="%%handle_call" type="erl"/>

    <p>How bad that unnecessary copy is depends on the contents of
    the record or the map.</p>

    <p>For example, if the <c>state</c> record is initialized like
    this:</p>
    <codeinclude file="efficiency_guide.erl" tag="%%init1" type="erl"/>

    <p>a list with 10000 elements (or about 20000 heap words) will be
    copied to the newly created process.</p>

    <p>An unncessary copy of 10000 element list can be bad enough, but it
    can get even worse if the <c>state</c> record contains <em>shared subterms</em>.
    Here is a simple example of a term with a shared subterm:</p>

    <code type="erl"><![CDATA[
{SubTerm, SubTerm}]]></code>

    <p>When a term is copied to another process, sharing of subterms
    will be lost and the copied term can be many times larger than the
    original term. For example:</p>

    <codeinclude file="efficiency_guide.erl" tag="%%init2" type="erl"/>

    <p>In the process that calls <c>init2/0</c>, the size of the
    <c>data</c> field in the <c>state</c> record will be 32 heap
    words. When the record is copied to the newly created process,
    sharing will be lost and the size of the copied <c>data</c> field
    will be 131070 heap words. More details about <seeguide
    marker="processes#loss-of-sharing">loss off sharing</seeguide> are
    found in a later section.</p>

    <p>To avoid the problem, outside of the fun extract only the
    fields of the record that are actually used:</p>

    <p><em>DO</em></p>
    <codeinclude file="efficiency_guide.erl" tag="%%fixed_acc1" type="erl"/>

    <p>Similarly, outside of the fun extract only the map elements
    that are actually used:</p>

    <p><em>DO</em></p>
    <codeinclude file="efficiency_guide.erl" tag="%%fixed_acc2" type="erl"/>
  </section>

  <section>
    <title>list_to_atom/1</title>

    <p>Atoms are not garbage-collected. Once an atom is created, it is never
    removed. The emulator terminates if the limit for the number
    of atoms (1,048,576 by default) is reached.</p>

    <p>Therefore, converting arbitrary input strings to atoms can be
    dangerous in a system that runs continuously.
    If only certain well-defined atoms are allowed as input,
    <seemfa marker="erts:erlang#list_to_existing_atom/1">list_to_existing_atom/1</seemfa>
    can be used
    to guard against a denial-of-service attack. (All atoms that are allowed
    must have been created earlier, for example, by simply using all of them
    in a module and loading that module.)</p>

    <p>Using <c>list_to_atom/1</c> to construct an atom that is passed to
    <c>apply/3</c> as follows, is quite expensive and not recommended
    in time-critical code:</p>
    <code type="erl">
apply(list_to_atom("some_prefix"++Var), foo, Args)</code>
  </section>

  <section>
    <title>length/1</title>

    <p>The time for calculating the length of a list is proportional to the
    length of the list, as opposed to <c>tuple_size/1</c>, <c>byte_size/1</c>,
    and <c>bit_size/1</c>, which all execute in constant time.</p>

    <p>Normally, there is no need to worry about the speed of <c>length/1</c>,
    because it is efficiently implemented in C. In time-critical code,
    you might want to avoid it if the input list could potentially be very
    long.</p>

    <p>Some uses of <c>length/1</c> can be replaced by matching.
    For example, the following code:</p>
    <code type="erl">
foo(L) when length(L) >= 3 ->
    ...</code>

    <p>can be rewritten to:</p>
    <code type="erl">
foo([_,_,_|_]=L) ->
   ...</code>

   <p>One slight difference is that <c>length(L)</c> fails if <c>L</c>
   is an improper list, while the pattern in the second code fragment
   accepts an improper list.</p>
  </section>

  <section>
    <title>setelement/3</title>

    <p><seemfa marker="erts:erlang#setelement/3">setelement/3</seemfa>
    copies the tuple it modifies. Therefore, updating a tuple in a loop
    using <c>setelement/3</c> creates a new copy of the tuple every time.</p>

    <p>There is one exception to the rule that the tuple is copied.
    If the compiler clearly can see that destructively updating the tuple would
    give the same result as if the tuple was copied, the call to
    <c>setelement/3</c> is replaced with a special destructive <c>setelement</c>
    instruction. In the following code sequence, the first <c>setelement/3</c>
    call copies the tuple and modifies the ninth element:</p>
    <code type="erl">
multiple_setelement(T0) ->
    T1 = setelement(9, T0, bar),
    T2 = setelement(7, T1, foobar),
    setelement(5, T2, new_value).</code>

    <p>The two following <c>setelement/3</c> calls modify
    the tuple in place.</p>

    <p>For the optimization to be applied, <em>all</em> the followings conditions
    must be true:</p>

    <list type="bulleted">
    <item>The indices must be integer literals, not variables or expressions.</item>
    <item>The indices must be given in descending order.</item>
    <item>There must be no calls to another function in between the calls to
    <c>setelement/3</c>.</item>
    <item>The tuple returned from one <c>setelement/3</c> call must only be used
    in the subsequent call to <c>setelement/3</c>.</item>
    </list>

    <p>If the code cannot be structured as in the <c>multiple_setelement/1</c>
    example, the best way to modify multiple elements in a large tuple is to
    convert the tuple to a list, modify the list, and convert it back to
    a tuple.</p>
  </section>

  <section>
    <title>size/1</title>

    <p><c>size/1</c> returns the size for both tuples and binaries.</p>

    <p>Using the BIFs <c>tuple_size/1</c> and <c>byte_size/1</c>
    gives the compiler and the runtime system more opportunities for
    optimization. Another advantage is that the BIFs give Dialyzer more
    type information.</p>
  </section>

  <section>
    <title>split_binary/2</title>
      <p>It is usually more efficient to split a binary using matching
      instead of calling the <c>split_binary/2</c> function.
      Furthermore, mixing bit syntax matching and <c>split_binary/2</c>
      can prevent some optimizations of bit syntax matching.</p>

        <p><em>DO</em></p>
        <code type="none"><![CDATA[
        <<Bin1:Num/binary,Bin2/binary>> = Bin,]]></code>
        <p><em>DO NOT</em></p>
        <code type="none">
        {Bin1,Bin2} = split_binary(Bin, Num)</code>
   </section>
</chapter>
