<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sergei Semichev</title>
    <description>The latest articles on DEV Community by Sergei Semichev (@dobro).</description>
    <link>https://dev.to/dobro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F205699%2F47aa6ff7-588c-450e-b268-be9b4a64c740.jpeg</url>
      <title>DEV Community: Sergei Semichev</title>
      <link>https://dev.to/dobro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dobro"/>
    <language>en</language>
    <item>
      <title>Erlang, Chess and Bitboards. The application that was supposed to appear one day</title>
      <dc:creator>Sergei Semichev</dc:creator>
      <pubDate>Fri, 02 Aug 2019 15:13:01 +0000</pubDate>
      <link>https://dev.to/dobro/erlang-chess-and-bitboards-the-application-that-was-supposed-to-appear-one-day-22ni</link>
      <guid>https://dev.to/dobro/erlang-chess-and-bitboards-the-application-that-was-supposed-to-appear-one-day-22ni</guid>
      <description>&lt;p&gt;I found that there was no Chess representation written in Erlang. So, I wrote &lt;strong&gt;Binbo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f-2cSUdi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8ecq4mukdp61gs7vzd1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f-2cSUdi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8ecq4mukdp61gs7vzd1w.png" alt="Binbo in Erlang shell"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/DOBRO/binbo"&gt;Binbo&lt;/a&gt; is a Chess representation written in pure Erlang using &lt;a href="https://www.chessprogramming.org/Bitboards"&gt;Bitboards&lt;/a&gt;. It is basically aimed to be used on game servers where people play chess online.&lt;/p&gt;

&lt;p&gt;It's called &lt;code&gt;Binbo&lt;/code&gt; because its ground is a &lt;strong&gt;bin&lt;/strong&gt;ary &lt;strong&gt;bo&lt;/strong&gt;ard containing only &lt;em&gt;zeros&lt;/em&gt; and &lt;em&gt;ones&lt;/em&gt; (&lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;) since this is the main meaning of Bitboards as an internal chessboard representation.&lt;/p&gt;

&lt;p&gt;Binbo also uses the &lt;a href="https://www.chessprogramming.org/Magic_Bitboards"&gt;Magic Bitboards&lt;/a&gt; approach for a &lt;strong&gt;blazing fast&lt;/strong&gt; move generation of sliding pieces (rook, bishop, and queen).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; it's not a chess engine but it could be a good starting point for it. It can play the role of a core (regarding move generation and validation) for multiple chess engines running on distributed Erlang nodes, since Binbo is an OTP application itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Blazing fast move generation and validation.&lt;/li&gt;
&lt;li&gt;No bottlenecks. Every game is an Erlang process (&lt;code&gt;gen_server&lt;/code&gt;) with its own game state.&lt;/li&gt;
&lt;li&gt;Ability to create as many concurrent games as many Erlang processes allowed in VM.&lt;/li&gt;
&lt;li&gt;Support for &lt;a href="https://ru.wikipedia.org/wiki/Portable_Game_Notation"&gt;PGN&lt;/a&gt; loading.&lt;/li&gt;
&lt;li&gt;All the chess rules are completely covered including:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/En_passant"&gt;En-passant move&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Castling"&gt;Castling&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Fifty-move_rule"&gt;Fifty-move rule&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Threefold_repetition"&gt;Threefold repetition&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.e4ec.org/immr.html"&gt;Draw by insufficient material&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Unicode chess symbols support for the board visualization right in Erlang shell:
♙ ♘ ♗ ♖ ♕ ♔ ♟ ♞ ♝ ♜ ♛ ♚&lt;/li&gt;
&lt;li&gt;UCI protocol support.&lt;/li&gt;
&lt;li&gt;Cross-platform application. It runs on Linux, Unix, Windows, and macOS.&lt;/li&gt;
&lt;li&gt;Ready for use on game servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Binbo and Magic Bitboards
&lt;/h2&gt;

&lt;p&gt;As mentioned above, Binbo uses &lt;a href="https://www.chessprogramming.org/Magic_Bitboards"&gt;Magic Bitboards&lt;/a&gt;, the fastest solution for move generation of sliding pieces (rook, bishop, and queen). Good explanations of this approach can also be found &lt;a href="https://stackoverflow.com/questions/16925204/sliding-move-generation-using-magic-bitboard/30862064#30862064"&gt;here&lt;/a&gt; and &lt;a href="http://vicki-chess.blogspot.com/2013/04/magics.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main problem is to find the &lt;em&gt;index&lt;/em&gt; which is then used to lookup legal moves of sliding pieces in a preinitialized move database. The formula for the &lt;em&gt;index&lt;/em&gt; is:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;in C/C++:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;magic_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;occupied&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;magic_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;in Erlang:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;MagicIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="nv"&gt;Occupied&lt;/span&gt; &lt;span class="ow"&gt;band&lt;/span&gt; &lt;span class="nv"&gt;Mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;MagicNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;bsr&lt;/span&gt; &lt;span class="nv"&gt;Shift&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;where:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Occupied&lt;/code&gt; is the bitboard of all pieces.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Mask&lt;/code&gt; is the attack mask of a piece for a given square.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MagicNumber&lt;/code&gt; is the magic number, see "&lt;a href="https://www.chessprogramming.org/Looking_for_Magics"&gt;Looking for Magics&lt;/a&gt;".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Shift = (64 - Bits)&lt;/code&gt;, where &lt;code&gt;Bits&lt;/code&gt; is the number of bits corresponding to attack mask of a given square.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All values for &lt;em&gt;magic numbers&lt;/em&gt; and &lt;em&gt;shifts&lt;/em&gt; are precalculated before and stored in &lt;a href="https://github.com/DOBRO/binbo/blob/master/include/binbo_magic.hrl"&gt;binbo_magic.hrl&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To be accurate, Binbo uses &lt;a href="https://www.chessprogramming.org/Magic_Bitboards#Fancy"&gt;Fancy Magic Bitboards&lt;/a&gt;. It means that all moves are stored in a table of its own (individual) size for each square. In &lt;em&gt;C/C++&lt;/em&gt; such tables are actually two-dimensional arrays and any move can be accessed by a simple lookup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;global_move_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;magic_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If detailed:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;moves_from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;global_move_table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;moves_from&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;magic_index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The size of &lt;code&gt;moves_from&lt;/code&gt; table depends on piece and square where it is placed on. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for rook on &lt;code&gt;A1&lt;/code&gt; the size of &lt;code&gt;moves_from&lt;/code&gt; is &lt;code&gt;4096&lt;/code&gt; (2^12 = 4096, 12 bits required for the attack mask);&lt;/li&gt;
&lt;li&gt;for bishop on &lt;code&gt;A1&lt;/code&gt; it is &lt;code&gt;64&lt;/code&gt; (2^6 = 64, 6 bits required for the attack mask).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are no two-dimensional arrays in Erlang, and no global variables which could help us to get the fast access to the move tables &lt;strong&gt;from everywhere&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, how does Binbo beat this? Well, it's simple :).&lt;/p&gt;

&lt;p&gt;Erlang gives us the power of &lt;em&gt;tuples&lt;/em&gt; and &lt;em&gt;maps&lt;/em&gt; with their blazing fast lookup of &lt;em&gt;elements/values&lt;/em&gt; by their &lt;em&gt;index/key&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Since the number of squares on the chessboard is the constant value (it's always &lt;strong&gt;64&lt;/strong&gt;, right?), our &lt;code&gt;global_move_table&lt;/code&gt; can be constructed as a &lt;em&gt;tuple&lt;/em&gt; of 64 elements, and each element of this &lt;em&gt;tuple&lt;/em&gt; is a &lt;em&gt;map&lt;/em&gt; containing the &lt;em&gt;key-value&lt;/em&gt; association as &lt;code&gt;MagicIndex =&amp;gt; Moves&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If detailed, for moves:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;GlobalMovesTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;MoveMap1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="nv"&gt;MoveMap64&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;where:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;MoveMap1&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;MagicIndex_1_1&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Moves_1_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nv"&gt;MagicIndex_1_K&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Moves_1_K&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="nv"&gt;MoveMap64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;MagicIndex_64_1&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Moves_64_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nv"&gt;MagicIndex_64_N&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Moves_64_N&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and then we lookup legal moves from a square, say, &lt;code&gt;E4&lt;/code&gt; (29th element of the &lt;em&gt;tuple&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;E4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nv"&gt;MoveMapE4&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;E4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;GlobalMovesTable&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nv"&gt;MovesFromE4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;MagicIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;MovesMapE4&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To calculate &lt;em&gt;magic index&lt;/em&gt; we also need the &lt;em&gt;attack mask&lt;/em&gt; for a given square. Every &lt;em&gt;attack mask&lt;/em&gt; generated is stored in a &lt;em&gt;tuple&lt;/em&gt; of 64 elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;GlobalMaskTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Mask1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mask2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="nv"&gt;Mask64&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;Mask1&lt;/code&gt;, &lt;code&gt;Mask2&lt;/code&gt;, ..., &lt;code&gt;Mask64&lt;/code&gt; are &lt;em&gt;bitboards&lt;/em&gt; (integers).&lt;/p&gt;

&lt;p&gt;Finally, if we need to get all moves from &lt;code&gt;E4&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;E4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nv"&gt;Mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;E4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;GlobalMaskTable&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nv"&gt;MagicIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;Occupied&lt;/span&gt; &lt;span class="ow"&gt;band&lt;/span&gt; &lt;span class="nv"&gt;Mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;MagicNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;bsr&lt;/span&gt; &lt;span class="nv"&gt;Shift&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nv"&gt;MoveMapE4&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;E4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;GlobalMovesTable&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nv"&gt;MovesFromE4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;MagicIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;MovesMapE4&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, no global variables? &lt;strong&gt;We make them global&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;How do we get the fastest access to the &lt;em&gt;move tables&lt;/em&gt; and to the &lt;em&gt;attack masks&lt;/em&gt; &lt;strong&gt;from everywhere&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://erlang.org/doc/man/ets.html"&gt;ETS&lt;/a&gt;? No! Using ETS as a storage for &lt;em&gt;static terms&lt;/em&gt; we get the overhead due to extra data copying during lookup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And now we are coming to the fastest solution.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When Binbo starts up, all &lt;em&gt;move tables&lt;/em&gt; are initialized. Once these tables (&lt;em&gt;tuples&lt;/em&gt;, actually) initialized, they are "injected" into &lt;strong&gt;dynamically generated modules compiled at Binbo start&lt;/strong&gt;. Then, to get the values, we just call a &lt;em&gt;getter function&lt;/em&gt; (&lt;code&gt;binbo_global:get/1&lt;/code&gt;) with the argument as the name of the corresponding dynamic module.&lt;/p&gt;

&lt;p&gt;This awesome trick is used in MochiWeb library, see module &lt;a href="https://github.com/mochi/mochiweb/blob/master/src/mochiglobal.erl"&gt;mochiglobal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using &lt;a href="http://erlang.org/doc/man/persistent_term.html"&gt;persistent_term&lt;/a&gt; (since OTP 21.2) for storing static data is also a good idea. But it doesn't seem to be a better way for the following reason with respect to dynamic modules. When Binbo stops, it gets them &lt;strong&gt;unloaded&lt;/strong&gt; as they are not necessary anymore. It should do the similar things for &lt;code&gt;persistent_term&lt;/code&gt; data, say, delete all &lt;em&gt;unused terms&lt;/em&gt; to free memory. In this case we run into the issue regarding scanning the &lt;em&gt;heaps&lt;/em&gt; in all processes.&lt;/p&gt;

&lt;p&gt;So, using &lt;code&gt;global&lt;/code&gt; dynamic modules with large static data seems to be more reasonable in spite of that fact that it significantly slows down the application startup due to the run-time compilation of these modules.&lt;/p&gt;

</description>
      <category>erlang</category>
      <category>functional</category>
      <category>showdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
