<?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: Justin Ethier</title>
    <description>The latest articles on DEV Community by Justin Ethier (@justinethier).</description>
    <link>https://dev.to/justinethier</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%2F855530%2Fbd63417e-070b-4331-a4a9-ae0f74508289.jpg</url>
      <title>DEV Community: Justin Ethier</title>
      <link>https://dev.to/justinethier</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/justinethier"/>
    <language>en</language>
    <item>
      <title>Troubleshooting a ZigBee PAN ID Conflict</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Fri, 10 Nov 2023 15:12:30 +0000</pubDate>
      <link>https://dev.to/justinethier/troubleshooting-a-zigbee-pan-id-conflict-pfb</link>
      <guid>https://dev.to/justinethier/troubleshooting-a-zigbee-pan-id-conflict-pfb</guid>
      <description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Zigbee" rel="noopener noreferrer"&gt;ZigBee&lt;/a&gt; is a network protocol that allows for home and building automation using low power wireless controllers.&lt;/p&gt;

&lt;p&gt;Last year I spent time troubleshooting a series of building networks which tore themselves apart shortly after being commissioned. In each case the network coordinator was raising a PAN ID conflict error and re-forming the network with a new PAN, causing devices to be stranded or split apart on two separate networks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Typical Cause of PAN ID Conflicts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://community.silabs.com/s/article/why-is-my-network-changing-pan-ids-ember-pan-id-changed-status-when-there-are?language=en_US" rel="noopener noreferrer"&gt;This article&lt;/a&gt; explains how corrupt packets can cause a conflict. The suggested workaround on the SiLabs EmberZNet stack is to set a threshold to ensure the coordinator only takes corrective action if more than 63 conflicts are reported in a minute. &lt;/p&gt;

&lt;p&gt;This threshold was in place on our building network, making packet corruption an extremely unlikely source of the problem. &lt;/p&gt;

&lt;h2&gt;
  
  
  Packet Captures to the Rescue
&lt;/h2&gt;

&lt;p&gt;After taking several captures with the Simplicity Studio &lt;a href="https://docs.silabs.com/simplicity-studio-5-users-guide/latest/ss-5-users-guide-tools-network-analyzer/" rel="noopener noreferrer"&gt;Network Analyzer&lt;/a&gt; a colleague found an inconsistency in ZigBee Beacon frames from various devices. &lt;/p&gt;

&lt;p&gt;Consider the following frames from two different devices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZigBee Beacon [15 bytes]
   - Protocol Id: ZigBee Pro (0x00)
   -    .... 0010 = Stack Profile: ZigBee Pro (2)
   -    0010 .... = Network Protocol Version: 0x02
   -    .... .1.. = Router Capacity: true
   -    .000 1... = Depth: 0x01
   -    1... .... = End Device Capacity: true
   - Extended PAN ID: 0123456789ABCDEF
   - Tx Offset: 0xFFFFFF
   - NWK Update ID: 0x01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZigBee Beacon [15 bytes]
   - Protocol Id: ZigBee Pro (0x00)
   -    .... 0010 = Stack Profile: ZigBee Pro (2)
   -    0010 .... = Network Protocol Version: 0x02
   -    .... .1.. = Router Capacity: true
   -    .111 1... = Depth: 0x0F
   -    1... .... = End Device Capacity: true
   - Extended PAN ID: FEDCBA9876543210
   - Tx Offset: 0xFFFFFF
   - NWK Update ID: 0x00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on these captures it became clear the root cause was due to an extended PAN ID that was reversed on some number of devices.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://zigbeealliance.org/wp-content/uploads/2019/11/docs-05-3474-21-0csg-zigbee-specification.pdf" rel="noopener noreferrer"&gt;ZigBee 3.0 Specification&lt;/a&gt; explains why this would be a problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;3.6.1.13.1 Detecting a PAN Id Conflict&lt;br&gt;
Any device that is operational on a network and receives an MLME-BEACON-NOTIFY.indication in which the PAN identifier of the beacon frame matches its own PAN identifier but the EPID value contained in the beacon payload is either not present or not equal to nwkExtendedPANID, shall be considered to have detected a PAN Identifier conflict.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is exactly what was happening on the network! Everything would continue to operate normally but the mismatched EPID values were causing conflicts to be reported at a higher rate than our threshold value.&lt;/p&gt;

&lt;p&gt;Once the threshold for these errors is exceeded (63 in a minute) the coordinator will select a new PAN ID and broadcast a network update to ask nodes to move to the new PAN. This is problematic because it often has the effect of splitting the network.&lt;/p&gt;

&lt;p&gt;This also would only be a problem when devices on the network are sending beacon requests, such as when a device is searching for a network. Typically once a network is commissioned the EPID is &lt;a href="https://community.silabs.com/s/article/what-is-an-extended-pan-id-and-how-is-it-used-x?language=en_US" rel="noopener noreferrer"&gt;not included in packets&lt;/a&gt; to save space since ZigBee is designed for low power consumption and low data rate applications:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Other than the scanning and joining processes, the EPID rarely appears in transmitted ZigBee packets due to its large overhead (8 bytes) in the header.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Fortunately for our team we were able to quickly identify a software bug that was the source of the reversed EPID and patch the system.&lt;/p&gt;

&lt;p&gt;But this represents an important consideration for ZigBee networks. Sometimes issues only become apparent when deploying a large-scale distributed network, such as during a customer deployment. For example, the commissioning procedure that led us to the conflict was tested in-house. However despite having dozens of devices on the test system the number of conflicts being raised was not large enough to exceed the 63 per minute threshold. To an end user the network continued to operate as if nothing was wrong. &lt;/p&gt;

&lt;p&gt;Perhaps more exhaustive testing would catch this before it hit the field. But that is often the case! With any large distributed system there will be some level of unintended behavior that - despite our best efforts - only manifests itself in a real-world application. We need to be prepared to deal with these unexpected issues when they do arise, and take the proper precautions to catch as many as possible before customers and production systems are affected.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>A Git Branch and Release Strategy for Product Teams</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Thu, 09 Mar 2023 01:28:55 +0000</pubDate>
      <link>https://dev.to/justinethier/a-git-branch-and-release-strategy-for-product-teams-4njh</link>
      <guid>https://dev.to/justinethier/a-git-branch-and-release-strategy-for-product-teams-4njh</guid>
      <description>&lt;p&gt;This post presents a git branch/release strategy intended for use by a team providing long-term development and support for a software product. &lt;/p&gt;

&lt;p&gt;The goal is to provide dedicated branches for QA and customer releases while isolating those branches from bleeding-edge development changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Strategy
&lt;/h2&gt;

&lt;p&gt;In this model the repository consists of three types of branches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dev&lt;/code&gt; for all development. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;qa&lt;/code&gt; to create pre-production builds for the test team.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;release&lt;/code&gt; to create production builds for release to customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All code is merged from &lt;code&gt;dev&lt;/code&gt; to &lt;code&gt;qa&lt;/code&gt; to &lt;code&gt;release&lt;/code&gt; by a  team lead or other responsible party, as development and testing progresses.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;dev&lt;/code&gt; branch could just as well be &lt;code&gt;main&lt;/code&gt; or whatever the repository's default branch is called.&lt;/p&gt;

&lt;p&gt;There will typically be several pairs of QA and Release branches, each with their own version string appended. For example &lt;code&gt;qa-1.0&lt;/code&gt;, &lt;code&gt;release-1.1&lt;/code&gt;, etc. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;dev&lt;/code&gt; branch could be versioned as well if there is a need for long-term support of an older version of the software. For example &lt;code&gt;dev-2&lt;/code&gt;. Its best if that can be avoided but for mature products there may be a need to support multiple major versions at the same time.&lt;/p&gt;

&lt;p&gt;In summary, here is the graph of a set of branches to handle the 1.0 and 1.1 releases of an example project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fld1v812pmslke23hzv3x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fld1v812pmslke23hzv3x.png" alt="Image description" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In each case there is more than one merge from &lt;code&gt;dev&lt;/code&gt; to &lt;code&gt;qa&lt;/code&gt; before we identify the final release build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Reviews
&lt;/h2&gt;

&lt;p&gt;An optional approach to lock down &lt;code&gt;dev&lt;/code&gt; and only allow changes into it via merge request. That gives the team an opportunity to perform a code review prior to code landing in &lt;code&gt;dev&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Such a policy would be team-dependent. It probably makes more sense on a larger team and/or for an established product where it is important to control code quality and limit risk.&lt;/p&gt;

&lt;p&gt;In this model the actual development would take place on feature branches. For example &lt;code&gt;dev-feature-1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Integration and Deployment
&lt;/h2&gt;

&lt;p&gt;Automated building and deployment is convenient to have for &lt;code&gt;dev&lt;/code&gt; in almost all cases.&lt;/p&gt;

&lt;p&gt;QA and Release merges are going to happen much less frequently than pushes to &lt;code&gt;dev&lt;/code&gt; but when they do we are going to want a build ASAP. So continuous integration is going to be essential for these branches to ensure builds happen automatically. &lt;/p&gt;

&lt;p&gt;Automated deployment may be useful as well depending on your product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tagging of Builds
&lt;/h2&gt;

&lt;p&gt;Most teams are going to want their continuous integration script to apply a tag to QA and Release builds. That way there is full traceability into what went into each build as well as the ability to branch directly from the tag in case a hotfix or emergency patch is required.&lt;/p&gt;

&lt;p&gt;Development builds are expected to be created frequently and tagging of them is probably not desirable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This strategy is not a one-size-fits-all solution. But it can work well in practice for products requiring a formal development and release process.&lt;/p&gt;

&lt;p&gt;How do you handle branches and releases for your products?&lt;/p&gt;

</description>
      <category>welcome</category>
    </item>
    <item>
      <title>Using Backticks as Syntactic Sugar in JavaScript and Scheme</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Thu, 23 Feb 2023 14:42:53 +0000</pubDate>
      <link>https://dev.to/justinethier/using-backticks-as-syntactic-sugar-in-javascript-and-scheme-c81</link>
      <guid>https://dev.to/justinethier/using-backticks-as-syntactic-sugar-in-javascript-and-scheme-c81</guid>
      <description>&lt;p&gt;ECMAScript 6 introduced the concept of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals" rel="noopener noreferrer"&gt;template literals&lt;/a&gt; to provide a convenient way to build up strings in JavaScript. &lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; let h = "Hello", w = "World";
&amp;gt; `${h} ${w}!
  ${h} ${w} from line 2`

"Hello World!
Hello World from line 2"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is reminiscent of using backticks in Scheme to construct lists using &lt;a href="https://conservatory.scheme.org/schemers/Documents/Standards/R5RS/HTML/r5rs-Z-H-7.html#%_sec_4.2.6" rel="noopener noreferrer"&gt;quasiquotation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; (let ((h 'hello)
      (w 'world))
  `(,h ,w !))

(hello world !)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe its not a coincidence that template literals were called &lt;a href="https://humanwhocodes.com/blog/2012/08/01/a-critical-review-of-ecmascript-6-quasi-literals/" rel="noopener noreferrer"&gt;quasi-literals&lt;/a&gt; when originally proposed:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This scheme extends EcmaScript syntax with syntactic sugar to allow libraries to provide DSLs that easily produce, query, and manipulate content from other languages that are immune or resistant to injection attacks such as XSS, SQL Injection, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Especially since there are no other &lt;a href="https://en.wikipedia.org/wiki/String_interpolation" rel="noopener noreferrer"&gt;commonly-used languages&lt;/a&gt; that use backticks for string interpolation.&lt;/p&gt;

&lt;p&gt;Anyway, thought this was an interesting observation on the evolution of the JavaScript language.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>systemdesign</category>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Detect a Cycle in a Linked List</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Sat, 11 Feb 2023 21:21:44 +0000</pubDate>
      <link>https://dev.to/justinethier/how-to-detect-a-cycle-in-a-linked-list-1o3n</link>
      <guid>https://dev.to/justinethier/how-to-detect-a-cycle-in-a-linked-list-1o3n</guid>
      <description>&lt;p&gt;When developing &lt;a href="https://github.com/justinethier/cyclone" rel="noopener noreferrer"&gt;Cyclone Scheme&lt;/a&gt; I discovered the latest &lt;a href="https://small.r7rs.org/attachment/r7rs.pdf" rel="noopener noreferrer"&gt;R&lt;sup&gt;7&lt;/sup&gt;RS&lt;/a&gt; Scheme language specification requires that several procedures handle circular lists. &lt;/p&gt;

&lt;p&gt;For example when comparing objects for equality:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even if its arguments are circular data structures, &lt;code&gt;equal?&lt;/code&gt;&lt;br&gt;
must always terminate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can't make a simple loop over the list because our code will keep running forever if one of the nodes points back to an earlier node. &lt;/p&gt;

&lt;p&gt;So what to do?&lt;/p&gt;

&lt;h2&gt;
  
  
  Floyd's Tortoise and Hare Algorithm
&lt;/h2&gt;

&lt;p&gt;Well, it turns out there is an elegantly simple &lt;a href="https://en.wikipedia.org/wiki/Cycle_detection" rel="noopener noreferrer"&gt;solution&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Robert W. Floyd's tortoise and hare algorithm moves two pointers at different speeds through the sequence of values until they both point to equal values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's demonstrate how it works.&lt;/p&gt;

&lt;p&gt;We start with a linked list of 5 nodes, &lt;code&gt;A&lt;/code&gt; through &lt;code&gt;E&lt;/code&gt;. Each one is linked in alphabetical order except node &lt;code&gt;E&lt;/code&gt; which links back to &lt;code&gt;A&lt;/code&gt;, forming a cycle.&lt;/p&gt;

&lt;p&gt;We will use two pointers to traverse the list. A slow pointer starting at the first node in the list, &lt;code&gt;A&lt;/code&gt;, and a fast pointer starting at &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fowliqe1uqvzrkem0czw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fowliqe1uqvzrkem0czw6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can make several iterations, each time advancing the slow pointer ahead one node and the fast pointer ahead by two nodes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05vshxw8cv4vvoaa438g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05vshxw8cv4vvoaa438g.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo41x0dnth8go0auuaov5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo41x0dnth8go0auuaov5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxnesb4eb6d5kxjxzpii.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxnesb4eb6d5kxjxzpii.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8d00gpt7ijs4n3gqlhs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8d00gpt7ijs4n3gqlhs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see the fast pointer reaches &lt;code&gt;E&lt;/code&gt; and starts back around at the front of the list. After four iterations it caches up to the slow pointer and both now point to &lt;code&gt;E&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Since the pointers are moving at different speeds they can only point to the same node if there is a cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  A JavaScript Implementation
&lt;/h2&gt;

&lt;p&gt;To implement a solution in JavaScript we start with the definition for each node in a singly-linked list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is our cycle detection algorithm. By having a &lt;code&gt;fast&lt;/code&gt; and &lt;code&gt;slow&lt;/code&gt; pointer traverse the list we can find cycles efficiently with only a small amount of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {Node} head
 * @return {boolean}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;hasCycle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no need to check for &lt;code&gt;slow === null&lt;/code&gt; because &lt;code&gt;fast&lt;/code&gt; will always reach the end of the list first.&lt;/p&gt;

&lt;p&gt;Also, we must ensure &lt;code&gt;fast.next&lt;/code&gt; is not &lt;code&gt;null&lt;/code&gt; before accessing &lt;code&gt;fast.next.next&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation in the Cyclone Scheme Runtime
&lt;/h2&gt;

&lt;p&gt;Going back to my original problem, perhaps it would be interesting to briefly discuss a real-world application of this algorithm.&lt;/p&gt;

&lt;p&gt;In Scheme lists are a fundamental data construct similar to linked lists in other languages. Their definition as a C structure is equivalent to &lt;code&gt;Node&lt;/code&gt; above with a value stored in &lt;code&gt;pair_car&lt;/code&gt; and &lt;code&gt;pair_cdr&lt;/code&gt; pointing to the next &lt;code&gt;pair_type&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Omit object header fields&lt;/span&gt;
  &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;pair_car&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;pair_cdr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;pair_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For various reasons the Cyclone runtime's implementation is more complicated than the JavaScript code above. &lt;a href="https://github.com/justinethier/cyclone/blob/bde930a18b1aed12dc833c605d5cec1738d65559/runtime.c#L917" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is Cyclone's function to determine if a list contains a cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And there you have it. Thanks for reading!&lt;/p&gt;

&lt;p&gt;Note this problem is also popular now as a &lt;a href="https://leetcode.com/problems/linked-list-cycle/" rel="noopener noreferrer"&gt;LeetCode&lt;/a&gt; interview question.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>computerscience</category>
      <category>codinginterviews</category>
    </item>
    <item>
      <title>Career Development by Planting Acorns</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Fri, 10 Feb 2023 16:32:41 +0000</pubDate>
      <link>https://dev.to/justinethier/career-development-by-planting-acorns-48g8</link>
      <guid>https://dev.to/justinethier/career-development-by-planting-acorns-48g8</guid>
      <description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Richard_Hamming"&gt;Richard Hamming&lt;/a&gt; gave a famous talk called &lt;a href="https://www.cs.virginia.edu/~robins/YouAndYourResearch.html"&gt;"You and Your Research"&lt;/a&gt; in which he had many great insights on doing world-class work, including this gem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The great scientists often make this error. They fail to continue to plant the little acorns from which the mighty oak trees grow. They try to get the big thing right off. And that isn't the way things go. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Something to think about when moving to a new project, new role, or an unfamiliar tech stack. Take the time to learn the little things, put in the work, and give those seeds the proper time to grow...&lt;/p&gt;

</description>
      <category>career</category>
    </item>
    <item>
      <title>Tail Call Optimization by Base Jumping off the Stack</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Mon, 09 Jan 2023 21:13:38 +0000</pubDate>
      <link>https://dev.to/justinethier/tail-call-optimization-by-base-jumping-off-the-stack-4mbl</link>
      <guid>https://dev.to/justinethier/tail-call-optimization-by-base-jumping-off-the-stack-4mbl</guid>
      <description>&lt;p&gt;Tail calls are the only means of iteration in most functional languages. So implementation support is absolutely critical. &lt;/p&gt;

&lt;p&gt;For example, Scheme requires tail call optimization as part of its &lt;a href="https://small.r7rs.org/attachment/r7rs.pdf" rel="noopener noreferrer"&gt;language specification (PDF)&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;3.5 Proper tail recursion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Implementations of Scheme are required to be properly tail-recursive. A Scheme implementation is properly tail-recursive if it supports an unbounded number of active tail calls. A call is active if the called procedure might still return. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Over the years various solutions have been developed to meet this requirement such as trampolines, &lt;code&gt;goto&lt;/code&gt;'s, compiler optimizations, etc. One of the most unusual was proposed by Henry Baker in his paper &lt;a href="https://github.com/justinethier/cyclone/blob/master/docs/research-papers/CheneyMTA.pdf" rel="noopener noreferrer"&gt;CONS Should Not CONS Its Arguments, Part II: Cheney on the M.T.A. (PDF)&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cheney on the M.T.A.
&lt;/h1&gt;

&lt;p&gt;Cheney on the M.T.A. requires writing a compiler and runtime. Code is converted into continuation passing style and compiled into a series of C functions. When the program runs these functions are called like normal C functions but they never return. The stack keeps growing and growing...&lt;/p&gt;

&lt;p&gt;The program periodically checks to see if a stack size limit is reached. When that happens a &lt;a href="https://en.wikipedia.org/wiki/Cheney%27s_algorithm" rel="noopener noreferrer"&gt;Cheney copying garbage collector&lt;/a&gt; is used to copy live data from the stack to the heap. Once all the live objects on the stack are copied the program calls &lt;a href="https://en.cppreference.com/w/c/program/longjmp" rel="noopener noreferrer"&gt;&lt;code&gt;longjmp&lt;/code&gt;&lt;/a&gt; to go back to the bottom of the stack, calls into the next function, and keep going.&lt;/p&gt;

&lt;p&gt;One way to think of this is that instead of using a trampoline we are going to BASE jump off the stack every so often:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdae7vvxfsh8dc98ng1oa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdae7vvxfsh8dc98ng1oa.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the one hand this is kind of insane 😮. Programs are not supposed to work this way! &lt;/p&gt;

&lt;p&gt;Then again, recursive calls are guaranteed to never cause a stack overflow because everything is periodically cleared from the stack. Thus Cheney on the M.T.A guarantees tail call optimization.&lt;/p&gt;

&lt;p&gt;In fact this approach provides all the "hard" stuff that a functional programming language runtime needs - tail call optimization, generational garbage collection, and continuations.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;

&lt;p&gt;Here are code examples from &lt;a href="https://github.com/justinethier/cyclone" rel="noopener noreferrer"&gt;Cyclone Scheme&lt;/a&gt; demonstrating how Cheney on the M.T.A works in practice.&lt;/p&gt;

&lt;p&gt;Cyclone's runtime uses the following function to set up a new trampoline. The bottom of the stack is explicitly marked using &lt;code&gt;setjmp&lt;/code&gt;. After a garbage collection code will resume execution on the next line after &lt;code&gt;setjmp&lt;/code&gt;. At that point the code finds the next function - &lt;code&gt;gc-&amp;gt;cont&lt;/code&gt;, our continuation - and calls into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void Cyc_start_trampoline(gc_thread_data * thd)
{
  // Tank, load the jump program
  setjmp(*(thd-&amp;gt;jmp_start));

  if (obj_is_not_closure(thd-&amp;gt;gc_cont)) {
    Cyc_apply_from_buf(thd, thd-&amp;gt;gc_num_args, thd-&amp;gt;gc_cont, thd-&amp;gt;gc_args);
  } else {
    closure clo = thd-&amp;gt;gc_cont;
   (clo-&amp;gt;fn)(thd, clo, thd-&amp;gt;gc_num_args, thd-&amp;gt;gc_args);
  }

  fprintf(stderr, "Internal error: should never have reached this line\n");
  exit(1);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The snippet below demonstrates how C functions may be written using Baker's approach. All compiler-generated and primitive functions that call into other functions must be written in this style:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object Cyc_make_vector(object cont, object len, object fill) {
  object v = NULL;
  int i;
  Cyc_check_int(len);

  // Memory for vector can be allocated directly on the stack
  v = alloca(sizeof(vector_type));

  // Populate vector object
  ((vector)v)-&amp;gt;tag = vector_tag;
  ... 

  // Check if GC is needed, then call into
  // continuation with the new vector
  return_closcall1(cont, v);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A macro &lt;code&gt;return_closcall1&lt;/code&gt; is used to check if the stack limit has been reached - if so a minor collection is triggered via &lt;code&gt;GC()&lt;/code&gt;. Otherwise another macro &lt;code&gt;closcall1&lt;/code&gt; is used to call into the next function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#define return_closcall1(td, clo, a1) {
 char top;
 object buf[1]; buf[0] = a1;
 if (stack_overflow(&amp;amp;top, (((gc_thread_data *)data)-&amp;gt;stack_limit))) {
     GC(td, clo, buf, 1);
     return; // Never reached
 } else {
     closcall1(td, (closure) (clo), buf);                                      
     return; // Never reached
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is &lt;code&gt;GC&lt;/code&gt;, the wrapper for Cyclone's minor garbage collector. The code retrieves locations of the top/bottom of the stack, calls into &lt;code&gt;gc_minor&lt;/code&gt; to collect objects using Cheney's algorithm, and the calls &lt;code&gt;longjmp&lt;/code&gt; to base jump back to the start of the trampoline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void GC(void *data, closure cont, object * args, int num_args)
{
  char tmp;
  object low_limit = &amp;amp;tmp;      // This is one end of the stack...
  object high_limit = ((gc_thread_data *) data)-&amp;gt;stack_start;

  int alloci = gc_minor(data, low_limit, high_limit, cont, args, num_args);
  ...

  // Let it all go, Neo...
  longjmp(*(((gc_thread_data *) data)-&amp;gt;jmp_start), 1);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is enough going on it &lt;code&gt;gc_minor&lt;/code&gt; that it is outside the scope of this article. But &lt;a href="https://github.com/justinethier/cyclone/blob/76668dc76c2653b1cf0d073fc2d2630b72dd51d8/runtime.c#L6191" rel="noopener noreferrer"&gt;the code&lt;/a&gt; is available on GitHub if you are curious.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;That's all for now. Thanks for reading! 🎉&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>c</category>
      <category>scheme</category>
    </item>
    <item>
      <title>Tail Call Optimization in JavaScript using Trampolines</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Thu, 29 Dec 2022 19:51:30 +0000</pubDate>
      <link>https://dev.to/justinethier/tail-call-optimization-in-javascript-59db</link>
      <guid>https://dev.to/justinethier/tail-call-optimization-in-javascript-59db</guid>
      <description>&lt;p&gt;Continuing on the previous article in this series. With some preparation and slight modifications to our existing code we can perform tail call optimization (TCO) to make an unlimited number of recursive function calls in JavaScript!&lt;/p&gt;

&lt;p&gt;Below is the full solution based on &lt;a href="https://stackoverflow.com/a/62376811/101258" rel="noopener noreferrer"&gt;this example&lt;/a&gt; from Stack Overflow. We'll break everything down in a moment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Tco {        
  constructor(func) {
    this.func = func;
  }
  execute() {
    let value = this;
    while (value instanceof Tco)
      value = value.func(); 
    return value;  
  }
}

const tco = (f) =&amp;gt; new Tco(f);

function adder(n) {
  const loop = (i) =&amp;gt; tco(() =&amp;gt; {
    if (i == n) {
      return n;
    }     
    return loop(i + 1);
  });

  return loop(0).execute();
};

console.log(adder(10)); 
console.log(adder(1000));
console.log(adder(100000));
console.log(adder(10000000));  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pi@raspberrypi:~/Documents $ node adder.js 
10
1000
100000
10000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Trampolines
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;Tco&lt;/code&gt; class defines an object with an &lt;code&gt;execute&lt;/code&gt; function that does the heavy lifting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    let value = this;
    while (value instanceof Tco)
      value = value.func(); 
    return value; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an example of a &lt;a href="https://en.wikipedia.org/wiki/Trampoline_(computing)" rel="noopener noreferrer"&gt;trampoline&lt;/a&gt;. Sadly, there is no trampoline emoji or I would throw one in here. Anyhow, this &lt;code&gt;while&lt;/code&gt; loop calls a function &lt;code&gt;value.func()&lt;/code&gt; that returns either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;Tco&lt;/code&gt; instance to indicate execution is still active. The trampoline will call into that instance again to make another recursive call, or&lt;/li&gt;
&lt;li&gt;A different type of object indicating recursion is complete. This &lt;code&gt;value&lt;/code&gt; is returned as the final result&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Helper Function
&lt;/h1&gt;

&lt;p&gt;A &lt;code&gt;tco&lt;/code&gt; function is defined as a helper to make the syntax cleaner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tco = (f) =&amp;gt; new Tco(f);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Modifying our Existing JavaScript Code
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;adder&lt;/code&gt; function's inner &lt;code&gt;loop&lt;/code&gt; is modified to return an instance of &lt;code&gt;Tco&lt;/code&gt; via our helper function. &lt;/p&gt;

&lt;p&gt;When we say &lt;code&gt;return loop&lt;/code&gt; we are returning that instance to the caller rather than calling into &lt;code&gt;loop&lt;/code&gt; directly! &lt;/p&gt;

&lt;p&gt;Note the &lt;code&gt;return n&lt;/code&gt; returns our final integer value, terminating the loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const loop = (i) =&amp;gt; tco(() =&amp;gt; {
    if (i == n) {
      return n;
    } 
    return loop(i + 1);
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we begin our loop by instantiating a &lt;code&gt;loop&lt;/code&gt; object and calling into its &lt;code&gt;execute&lt;/code&gt; function to start the &lt;code&gt;Tco&lt;/code&gt; object's &lt;code&gt;while&lt;/code&gt; loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return loop(0).execute();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;While this pattern might not be a good idea for writing day to day code it can be a useful tool. Interpreters written in an imperative language such as JavaScript often use a trampoline to implement tail call optimization for the language that they are hosting. For example this would be an excellent start to the core of a Lisp interpreter in JavaScript.&lt;/p&gt;

&lt;p&gt;And that's it! Thanks for reading 👍&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>What is Tail Call Optimization?</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Tue, 27 Dec 2022 16:30:08 +0000</pubDate>
      <link>https://dev.to/justinethier/tail-call-optimization-d5l</link>
      <guid>https://dev.to/justinethier/tail-call-optimization-d5l</guid>
      <description>&lt;h1&gt;
  
  
  Recursive Calls in JavaScript
&lt;/h1&gt;

&lt;p&gt;Programming languages often limit the number of nested calls a recursive function is allowed to make.&lt;/p&gt;

&lt;p&gt;Consider this simple example in JavaScript. An &lt;code&gt;adder&lt;/code&gt; function recursively calls an inner function &lt;code&gt;loop&lt;/code&gt; exactly &lt;code&gt;n&lt;/code&gt; times and returns &lt;code&gt;n&lt;/code&gt; as the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function adder(n) {
  function loop (i) {
    if (i == n) {
      return n;
    }
    return loop(i + 1);
  }

  return loop(0);
}

console.log(adder(10));
console.log(adder(1000));
console.log(adder(100000));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code works fine for small values of &lt;code&gt;n&lt;/code&gt;. But with larger values eventually we run out of stack space and crash 💥&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pi@raspberrypi:~/Documents $ node adder.js
10
1000

/home/pi/Documents/adder.js:2
  function loop (i) {
                ^
RangeError: Maximum call stack size exceeded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is that &lt;code&gt;loop&lt;/code&gt; keeps getting added to the call stack for subsequent &lt;code&gt;i&lt;/code&gt; values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adder(10)
loop(0)
loop(1)
loop(2)
loop(3)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we reach the end of the stack we are done. And there is only 492 Kb of stack space on our test system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pi@raspberrypi:~/Documents $ node --v8-options | grep -B0 -A1 stack_size
  --stack_size (default size of stack region v8 is allowed to use (in kBytes))
        type: int  default: 492
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Tail Call Optimization
&lt;/h1&gt;

&lt;p&gt;This is where we leave off with JavaScript (for now). &lt;/p&gt;

&lt;p&gt;But there is more to the story. Some other languages and tooling support a concept called tail call optimization (TCO) that prevents the call stack from growing indefinitely. &lt;/p&gt;

&lt;p&gt;In a language with TCO the call stack grows no larger than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adder(10)
loop(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subsequent calls to &lt;code&gt;loop&lt;/code&gt; are not added to the stack. Or at least conceptually we can view it this way - the actual implementation details can vary from language to language. But the point is that the stack no longer grows indefinitely, so we can make unlimited use of recursive functions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Recursive Calls in Scheme
&lt;/h1&gt;

&lt;p&gt;For example, &lt;code&gt;adder&lt;/code&gt; works just fine when implemented in Scheme, which requires TCO as part of its language specification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(import (scheme base) 
        (scheme write))

(define (adder n) 
  (define (loop i)
    (if (= i n)
        n
        (loop (+ i 1))))
  (loop 0))

(write (adder 10)) (newline)
(write (adder 1000)) (newline)
(write (adder 100000)) (newline)
(write (adder 10000000)) (newline)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pi@raspberrypi:~/Documents $ cyclone adder.scm
pi@raspberrypi:~/Documents $ ./adder
10
1000
100000
10000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code runs fine even for a massive value such as &lt;code&gt;10,000,000&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;So, does tail call optimization make Scheme "better" than JavaScript? Not at all! Each language just emphasizes a different coding style. Functional languages such as Scheme, Haskell, and Erlang typically use recursion for looping. Without TCO they would be useless.&lt;/p&gt;

&lt;p&gt;In contrast imperative languages such as JavaScript, Go, and C use iteration for looping with &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;foreach&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, and friends. Since this is the widely accepted style there just isn't a need to optimize for recursion in these languages.&lt;/p&gt;

&lt;p&gt;Alright, that's all for now. &lt;br&gt;
Cheers! 🎉&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>computerscience</category>
      <category>scheme</category>
      <category>functionalprogrammi</category>
    </item>
    <item>
      <title>Building a Log-Structured Merge Tree in Go</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Thu, 15 Dec 2022 22:08:22 +0000</pubDate>
      <link>https://dev.to/justinethier/log-structured-merge-trees-1jha</link>
      <guid>https://dev.to/justinethier/log-structured-merge-trees-1jha</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Last year I read &lt;a href="https://austinhenley.com/blog/morechallengingprojects.html" rel="noopener noreferrer"&gt;more challenging projects every programmer should try&lt;/a&gt; and decided to take a deep dive into researching solutions for a key-value data store.&lt;/p&gt;

&lt;p&gt;There are two major technologies used in this space. Relational databases typically use B-trees to persistently store data. Alternatively many newer storage solutions use the log-structured merge tree (LSM tree).  &lt;/p&gt;

&lt;p&gt;LSM trees are specifically designed to handle write-heavy workloads. They are used in many popular NoSQL databases including Apache Cassandra, Elasticsearch, Google Bigtable, Apache HBase, and InfluxDB. As well as embedded data stores such as LevelDB and RocksDB.&lt;/p&gt;

&lt;p&gt;This article provides implementation details for the LSM tree based project &lt;a href="https://github.com/justinethier/keyva" rel="noopener noreferrer"&gt;keyva&lt;/a&gt; that I wrote to better understand how all of this works. The details are generic and cover concepts applicable to other LSM tree implementations.&lt;/p&gt;

&lt;h1&gt;
  
  
  High-Level Design
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfse6k2tguaqa0ujy05i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfse6k2tguaqa0ujy05i.png" alt="Top-level data flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data is always added to an LSM tree using sequential writes. This append-only approach allows for blazingly fast write operations but does require subsequent compaction to free extra records written when a key is updated or deleted.&lt;/p&gt;

&lt;p&gt;The MemTable, a data structure stored entirely in memory, is initially used to store new data. Operations here are very fast but space is limited and the data cannot be retained if the process is restarted. &lt;/p&gt;

&lt;p&gt;In order to recover data across restarts, the same data is also appended to a Write Ahead Log (WAL). The WAL is a simple append-only log that contains a single record for each operation made to the LSM tree.&lt;/p&gt;

&lt;p&gt;Eventually the MemTable will become too large to efficiently hold in memory and the data is flushed to a Sorted String Table (SST) file on disk. SST files are indexed and immutable, allowing fast concurrent data access. Eventually when enough SST files are generated a background job will compact them and merge the data into a new "level" of SST files. This gives the tree a chance to remove redundant records and efficiently re-organize data.&lt;/p&gt;

&lt;p&gt;SST files can efficiently serve large data sets. For example, Google Bigtable uses log-structured storage and is designed to scale to the petabyte range across a cluster of servers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Data Model
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Records
&lt;/h2&gt;

&lt;p&gt;Keyva uses a LSM tree to store data in terms of key/value pairs. Each key is an UTF-8 encoded string and each value is a sequence of bytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inserts and Updates
&lt;/h2&gt;

&lt;p&gt;A new key/value is inserted into the LSM tree by first being added to the MemTable and WAL, as depicted in the high level design.&lt;/p&gt;

&lt;p&gt;You may be surprised to learn that an update is added to the LSM tree in the exact same manner as an insert! &lt;/p&gt;

&lt;p&gt;The only difference for an update is that if the key already resides in the MemTable it will be overwritten with the new value. But if an existing key has already been flushed to disk as part of an SST file the old data will remain on disk for some time until the new key/value from the update is eventually merged into that SST level.&lt;/p&gt;

&lt;p&gt;So, both insert and update operations are incredibly efficient but their simplicity makes read a bit more complicated. Let's look at that next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reads
&lt;/h2&gt;

&lt;p&gt;So, when reading data an LSM tree must find the most recent value for a given key. Thus any read operation must start with the MemTable before moving to SST level 0, level 1, etc.&lt;/p&gt;

&lt;p&gt;Once read finds a key it will return with that first value that it has found. So in the case of an update it will simply ignore any previous values for a key that still reside in higher SST levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deletes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3h3d7chwayc91529xdl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3h3d7chwayc91529xdl.png" alt="Tombstone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data cannot be deleted directly from an SST. Instead the key is flagged as deleted and the data is deleted later when the SST is compacted. These flagged records are called tombstones.&lt;/p&gt;

&lt;p&gt;You can see the &lt;code&gt;Deleted&lt;/code&gt; flag used in our implementation:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type SstEntry struct {
    Key     string
    Value   []byte
    Deleted bool
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Value&lt;/code&gt; may be stored as an empty array for a deleted record, so at least we save a bit of space there.&lt;/p&gt;

&lt;p&gt;Unfortunately a tombstone cannot be immediately removed when its SST is compacted. In order to guarantee all of the old records for a key are removed the tombstone must reach the highest SST level in the tree. At that point it can be safely removed along with any corresponding value(s) for the key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write Amplification
&lt;/h2&gt;

&lt;p&gt;Write amplification is the ratio of the amount of data written to the LSM tree versus the amount of data written to disk. The same data may be written to disk multiple times as a key/value is promoted from one level of the SST to another. To increase performance an important consideration is to minimize the number of repeated disk writes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Data Structures
&lt;/h1&gt;

&lt;h2&gt;
  
  
  MemTable
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f1mi9nh0wrqdw5s1qxv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f1mi9nh0wrqdw5s1qxv.png" alt="Binary tree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All data added to the LSM tree is initially stored in Memtable, essentially an in-memory cache.&lt;/p&gt;

&lt;p&gt;Data in the MemTable needs to be arranged for fast access and ideally for low-cost concurrent read/write operations. A self-balanced tree such as a red-black tree can work well for this purpose. Our implementation uses a &lt;a href="https://en.wikipedia.org/wiki/Skip_list" rel="noopener noreferrer"&gt;skip list&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If a key already exists in the table when a request is received the value will be updated directly. This is different than the other data structures employed by the LSM tree, which are immutable.&lt;/p&gt;

&lt;p&gt;Deletes must be retained in the table as well. It is important to store a tombstone in case the key still contains data in the SST. The deletion will be resolved later when we compact SST files.&lt;/p&gt;

&lt;p&gt;Finally, when the MemTable reaches a certain threshold it must be flushed to disk. A potential optimization here is to allocate a new MemTable and designate the current MemTable as read-only. The old table can then be set off to the side for a background job to write it to disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write Ahead Log
&lt;/h2&gt;

&lt;p&gt;The WAL is a plain-text file containing a dump of all operations on the table. Essentially a transaction log of all operations on the MemTable.&lt;/p&gt;

&lt;p&gt;This allows reconstructing the in-memory portion of the tree in the event of service restart for data that has not been flushed to SST yet.&lt;/p&gt;

&lt;p&gt;In our implementation a separate WAL file is used for each MemTable. After a MemTable is written to disk its WAL file is purged, as the data is now retained in persistent storage by an SST. This prevents infinite growth of the WAL.  &lt;/p&gt;

&lt;p&gt;Finally, data is not organized efficiently within the WAL. So we only want to use it as a means of data recovery for the MemTable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorted String Table
&lt;/h2&gt;

&lt;p&gt;SST files are the primary data representation for storing an LSM tree on disk. Each one contains a series of key/values sorted by key:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwgt6i9t5qi3a647lvtm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwgt6i9t5qi3a647lvtm.png" alt="Example SST file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each file is immutable, making it easier to access data concurrently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sparse Index
&lt;/h3&gt;

&lt;p&gt;A sparse index may be used to find data contained in an SST file. The index does not need to contain all keys since data is sorted. Instead it may include every Nth key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ms5mygkill7b45mbot8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ms5mygkill7b45mbot8.png" alt="SST file with sparse index"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Bloom Filter
&lt;/h3&gt;

&lt;p&gt;A bloom filter is used to determine if an SST might contain a key before we check the SST. If the bloom filter cannot find a key then we know the key cannot be contained in the corresponding SST.&lt;/p&gt;

&lt;p&gt;This helps speed up read operations by reducing the amount of disk accesses when reading data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F941rymvahuvdmoapidc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F941rymvahuvdmoapidc7.png" alt="bloom filter data flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Layout
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Level
&lt;/h4&gt;

&lt;p&gt;SST files are organized into a series of multiple levels starting at level 0. Each level contains more data than the last and the maximum number of levels is configurable. Each level also contains multiple SST files. For example consider the following SST files in level 0:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44liu6dsatyf2wa4rjkh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44liu6dsatyf2wa4rjkh.png" alt="SST file levels"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As shown above files at level 0 may contain overlapping data. For example, observe how the first file contains a key for "Tucson" while the first key in the second file is "Atlanta". &lt;/p&gt;

&lt;p&gt;This ordering is necessary as files are added on-demand as the MemTable reaches capacity. The problem is that in order to find the most recent value for a key in level 0 each SST file must be checked. We need to start from the most recent file and work back to the oldest file.&lt;/p&gt;

&lt;p&gt;Higher levels are arranged more efficiently. Consider the same data after being merged to level 1:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbno70tl0glrrpnw5gl63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbno70tl0glrrpnw5gl63.png" alt="Merged SST data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see data is guaranteed to be in sorted order across all files in this level. A single binary search may be used to find the SST file containing a given key.&lt;/p&gt;

&lt;p&gt;As a result we probably want to minimize the amount of data in level 0, especially for a large dataset.&lt;/p&gt;

&lt;p&gt;Each subsequent SST level will contain more data than the previous. However if each subsequent level contains an order of magnitude more data than the previous there do not need to be many levels.&lt;/p&gt;

&lt;h4&gt;
  
  
  Segment
&lt;/h4&gt;

&lt;p&gt;Data is divided into segments on disk, one per SST file.&lt;/p&gt;

&lt;p&gt;Each segment also contains a header (sequence number) and an index.&lt;/p&gt;

&lt;h4&gt;
  
  
  Block
&lt;/h4&gt;

&lt;p&gt;Data within an SST is divided into blocks. There is one sparse index per block.&lt;/p&gt;

&lt;p&gt;SST files may be binary files that are optionally compressed to save space.&lt;/p&gt;

&lt;h1&gt;
  
  
  Merge
&lt;/h1&gt;

&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/K-way_merge_algorithm" rel="noopener noreferrer"&gt;k-way merge algorithm&lt;/a&gt; is used to combine data from many SST files into a new series of SST files. Or alternatively to compact data within a single SST level.&lt;/p&gt;

&lt;p&gt;In keyva, &lt;a href="https://github.com/justinethier/keyva/blob/e6ace48e588fc7eb6c1e98128c3a5de00280ee56/lsm/sst/compact.go#L33" rel="noopener noreferrer"&gt;&lt;code&gt;sst.Compact&lt;/code&gt;&lt;/a&gt; implements a streaming merge algorithm intended to scale up to large datasets. For each SST file a single record containing the latest string and a file handle are added to a min heap. The next record for the output file is then taken from the top of the heap and written to the current output SST file. A new record from the source SST is added back to the heap, and the process continues until all SST data is merged.&lt;/p&gt;

&lt;p&gt;By using a min heap we can efficiently write new SST data in sorted order even if we are merging data from a large number of source SST files. &lt;/p&gt;

&lt;p&gt;Data can be merged at regular intervals or at certain thresholds. For example a time series database might merge data at certain time intervals (daily, hourly, etc).&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy1zvj8x9z83bdnmdf6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy1zvj8x9z83bdnmdf6q.png" alt="Summertime"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there you have it. Thanks for reading!&lt;/p&gt;

&lt;p&gt;The full source code for my sample implementation is available on &lt;a href="https://pkg.go.dev/github.com/justinethier/keyva/lsm" rel="noopener noreferrer"&gt;pkg.go.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Key-value database (&lt;a href="https://en.wikipedia.org/wiki/Key%E2%80%93value_database" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;B-tree data structure (&lt;a href="https://en.wikipedia.org/wiki/B-tree" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;How I built a key value store in Go (&lt;a href="https://medium.com/@naqvi.jafar91/how-i-built-a-key-value-store-in-go-bd89f68062a8" rel="noopener noreferrer"&gt;web&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Badger: Fast key-value DB in Go (&lt;a href="https://github.com/dgraph-io/badger" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Awesome Go Storage (&lt;a href="https://github.com/gostor/awesome-go-storage" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;LSM tree paper (&lt;a href="https://www.cs.umb.edu/~poneil/lsmtree.pdf" rel="noopener noreferrer"&gt;PDF&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;SSTable and Log Structured Storage: LevelDB (&lt;a href="https://www.igvita.com/2012/02/06/sstable-and-log-structured-storage-leveldb/" rel="noopener noreferrer"&gt;web&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Log Structured Merge Trees (&lt;a href="https://medium.com/swlh/log-structured-merge-trees-9c8e2bea89e8" rel="noopener noreferrer"&gt;web&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>lsmtree</category>
      <category>go</category>
      <category>database</category>
      <category>nosql</category>
    </item>
    <item>
      <title>Porting a simple Mark-Sweep Garbage Collector to Zig</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Fri, 20 May 2022 18:21:42 +0000</pubDate>
      <link>https://dev.to/justinethier/porting-a-simple-mark-sweep-garbage-collector-to-zig-eg5</link>
      <guid>https://dev.to/justinethier/porting-a-simple-mark-sweep-garbage-collector-to-zig-eg5</guid>
      <description>&lt;p&gt;I recently completed &lt;a href="https://github.com/justinethier/zig-mark-sweep-gc" rel="noopener noreferrer"&gt;my first Zig project&lt;/a&gt; - a port of Bob Nystrom's simple mark-sweep garbage collector (a modern classic!) from C to Zig. &lt;/p&gt;

&lt;p&gt;Since &lt;a href="https://ziglang.org/" rel="noopener noreferrer"&gt;Zig&lt;/a&gt; is a relatively new language I thought it would be helpful to give an overview of the experience and talk about the tooling.&lt;/p&gt;

&lt;p&gt;This post explains a few parts of the program but I can't do justice to &lt;a href="https://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/" rel="noopener noreferrer"&gt;Bob's original article&lt;/a&gt; which I highly recommend reading. His C implementation is included in the project repo and is also available &lt;a href="https://github.com/munificent/mark-sweep" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyway, off we go...&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Zig
&lt;/h2&gt;

&lt;p&gt;The installation process is very simple. Just download the latest version from the &lt;a href="https://ziglang.org/download/" rel="noopener noreferrer"&gt;Releases page&lt;/a&gt;, extract to a folder, and add to your path.&lt;/p&gt;

&lt;p&gt;For example here is how Zig is installed for this project's continuous integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://ziglang.org/download/0.9.1/zig-linux-x86_64-0.9.1.tar.xz
&lt;span class="nb"&gt;tar &lt;/span&gt;xf zig-linux&lt;span class="k"&gt;*&lt;/span&gt;.tar.xz
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;/zig-linux-x86_64-0.9.1"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$GITHUB_PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A real installation would put the files somewhere more appropriate but this works just fine for our CI.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;zig&lt;/code&gt; comes as a large statically-linked executable. No dependencies required 👍.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vim Plugin
&lt;/h2&gt;

&lt;p&gt;Out of the box Vim works well enough as an editor for Zig but the experience is a bit underwhelming. So I installed the &lt;a href="https://github.com/ziglang/zig.vim" rel="noopener noreferrer"&gt;Vim configuration for Zig&lt;/a&gt; plugin get syntax highlighting.&lt;/p&gt;

&lt;p&gt;As an unexpected bonus:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This plugin enables automatic code formatting on save by default using &lt;code&gt;zig fmt&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Much like with Go its super handy to be able to just &lt;em&gt;not worry&lt;/em&gt; about code formatting. On top of that &lt;code&gt;zig fmt&lt;/code&gt; also catches basic syntax errors:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsxt5or9jetamsa9vx15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsxt5or9jetamsa9vx15.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tend to save frequently when coding so this provides constant feedback on the state of the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Printing
&lt;/h2&gt;

&lt;p&gt;I just used debug printing to write output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="py"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;print&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Collected {} objects, {} remaining.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;numObjects&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;numObjects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;numObjects&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An interesting observation is that instead of C varargs Zig uses an &lt;a href="https://ziglang.org/documentation/master/#Anonymous-List-Literals" rel="noopener noreferrer"&gt;anonymous struct&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  While Loops, If's, Optionals, and More
&lt;/h2&gt;

&lt;p&gt;Zig has many improvements over standard C syntax.&lt;/p&gt;

&lt;p&gt;Increment as part of the loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;stack_size&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unbox &lt;a href="https://ziglang.org/documentation/master/#Optionals" rel="noopener noreferrer"&gt;optionals&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handle &lt;a href="https://ziglang.org/documentation/master/#Error-Union-Type" rel="noopener noreferrer"&gt;error unions&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pushPair&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other miscellaneous improvements over C include standard naming conventions (underscores in names for non-callable variables) and a cleaner boolean type.&lt;/p&gt;

&lt;p&gt;It is also helpful to define functions as part of a &lt;code&gt;struct&lt;/code&gt; type, allowing a more natural organization of code. Though this has been a standard feature in most languages for a long time now. &lt;a href="https://stackoverflow.com/a/13125960/101258" rel="noopener noreferrer"&gt;Including C++&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pointers
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;sweep&lt;/code&gt; function uses a pointer-to-pointer to walk the linked list of all objects and unlink unused objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sweep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;firstObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;marked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="cm"&gt;/* This object wasn't reached, so remove it from the list and free it. */&lt;/span&gt;
      &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;unreached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unreached&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unreached&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;numObjects&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="cm"&gt;/* This object was reached, so unmark it (for the next GC) and move on to
       the next. */&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;marked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perhaps surprisingly, this function can be expressed line for line in Zig, just with a fresh new syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;sweep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;first_object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;marked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// This object wasn't reached, so remove it from the list and free it.&lt;/span&gt;
            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;unreached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.*&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unreached&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;num_objects&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// This object was reached, so unmark it (for the next GC) and move on to&lt;/span&gt;
            &lt;span class="c"&gt;// the next.&lt;/span&gt;
            &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;marked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;next&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;All of the tests were ported over to &lt;a href="https://ziglang.org/documentation/master/#Zig-Test" rel="noopener noreferrer"&gt;test declarations&lt;/a&gt;. These can be invoked via &lt;code&gt;zig test mark-sweep.zig&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;test&lt;/span&gt; &lt;span class="s"&gt;"test 1"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;allocator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test 1: Objects on stack are preserved.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;VM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pushInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pushInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;num_objects&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deinit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another important point! In Zig one does not call &lt;code&gt;malloc&lt;/code&gt; to allocate memory. Instead one of many allocators is used to allocate memory in the way that is most appropriate for the situation at hand. Our code is organized like a typical library where any allocator may be passed in and retained for memory allocations over the life of a VM instance. &lt;/p&gt;

&lt;p&gt;For testing we use &lt;code&gt;testing.allocator&lt;/code&gt; which fails the test case if any memory is leaked. This enhances our test as &lt;code&gt;vm.deinit()&lt;/code&gt; removes all of the &lt;a href="https://www.memorymanagement.org/glossary/r.html#term-root" rel="noopener noreferrer"&gt;root objects&lt;/a&gt; and performs a collection. If our code is working properly all allocated memory will be freed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging with gdb
&lt;/h2&gt;

&lt;p&gt;Having debugged C extensively &lt;code&gt;gdb&lt;/code&gt; I was shocked that it &lt;em&gt;Just Works&lt;/em&gt; for debugging Zig code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;justin@ubuntu:~/Documents/zig-mark-sweep-gc&lt;span class="nv"&gt;$ &lt;/span&gt;make
zig build-exe mark-sweep.zig
justin@ubuntu:~/Documents/zig-mark-sweep-gc&lt;span class="nv"&gt;$ &lt;/span&gt;./mark-sweep 
Performance Test.
Collected 20000 objects, 0 remaining.
justin@ubuntu:~/Documents/zig-mark-sweep-gc&lt;span class="nv"&gt;$ &lt;/span&gt;gdb mark-sweep 
GNU gdb &lt;span class="o"&gt;(&lt;/span&gt;Ubuntu 9.1-0ubuntu1&lt;span class="o"&gt;)&lt;/span&gt; 9.1
Copyright &lt;span class="o"&gt;(&lt;/span&gt;C&lt;span class="o"&gt;)&lt;/span&gt; 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type &lt;span class="s2"&gt;"show copying"&lt;/span&gt; and &lt;span class="s2"&gt;"show warranty"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;details.
This GDB was configured as &lt;span class="s2"&gt;"x86_64-linux-gnu"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Type &lt;span class="s2"&gt;"show configuration"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;configuration details.
For bug reporting instructions, please see:
&amp;lt;http://www.gnu.org/software/gdb/bugs/&amp;gt;.
Find the GDB manual and other documentation resources online at:
    &amp;lt;http://www.gnu.org/software/gdb/documentation/&amp;gt;.

For &lt;span class="nb"&gt;help&lt;/span&gt;, &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="s2"&gt;"help"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Type &lt;span class="s2"&gt;"apropos word"&lt;/span&gt; to search &lt;span class="k"&gt;for &lt;/span&gt;commands related to &lt;span class="s2"&gt;"word"&lt;/span&gt;...
Reading symbols from mark-sweep...
&lt;span class="o"&gt;(&lt;/span&gt;gdb&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;break &lt;/span&gt;VM.sweep
Breakpoint 1 at 0x23091c: file /home/justin/Documents/zig-mark-sweep-gc/mark-sweep.zig, line 91.
&lt;span class="o"&gt;(&lt;/span&gt;gdb&lt;span class="o"&gt;)&lt;/span&gt; run
Starting program: /home/justin/Documents/zig-mark-sweep-gc/mark-sweep 
Performance Test.

Breakpoint 1, VM.sweep &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x7fffffffd938&lt;span class="o"&gt;)&lt;/span&gt; at /home/justin/Documents/zig-mark-sweep-gc/mark-sweep.zig:91
91              var object &lt;span class="o"&gt;=&lt;/span&gt; &amp;amp;&lt;span class="o"&gt;(&lt;/span&gt;self.first_object&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;gdb&lt;span class="o"&gt;)&lt;/span&gt; n
92              &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;object.&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; |obj| &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;gdb&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's it for now. All in all this was a great first experience with Zig and I look forward to writing more Zig in the near future.&lt;/p&gt;

&lt;p&gt;Useful links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ziglang.org/documentation/master/" rel="noopener noreferrer"&gt;Zig Language Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code" rel="noopener noreferrer"&gt;How to read the standard library source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ziglang.org/documentation/master/std/" rel="noopener noreferrer"&gt;Zig Standard Library Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ziglearn.org/" rel="noopener noreferrer"&gt;Zig Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>zig</category>
      <category>algorithms</category>
      <category>c</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Kaprekar's Constant in JavaScript</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Sat, 07 May 2022 23:33:18 +0000</pubDate>
      <link>https://dev.to/justinethier/kaprekars-constant-in-javascript-if7</link>
      <guid>https://dev.to/justinethier/kaprekars-constant-in-javascript-if7</guid>
      <description>&lt;p&gt;So I was scrolling TikTok's the other day, as one does, when I saw the number &lt;code&gt;6174&lt;/code&gt; featured in one of the videos. Turns out this is a special number called Kaprekar's constant, named after Indian mathematician &lt;a href="https://en.wikipedia.org/wiki/D._R._Kaprekar"&gt;D. R. Kaprekar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Start with a four-digit number with at least two different digits. If a number has less than four digits we can pad it with zeros. For example, &lt;code&gt;42&lt;/code&gt; becomes &lt;code&gt;0042&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Arrange the digits from largest to smallest and again from smallest to largest to get maximum and minimum values.&lt;/li&gt;
&lt;li&gt;Subtract minimum from maximum.&lt;/li&gt;
&lt;li&gt;Repeat these steps. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result will always converge to &lt;code&gt;6174&lt;/code&gt; after a small number of iterations.&lt;/p&gt;

&lt;p&gt;For example,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;628&lt;/code&gt;&lt;br&gt;
&lt;code&gt;8620 - 268 = 8352&lt;/code&gt;&lt;br&gt;
&lt;code&gt;8532 - 2358 = 6174&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's tedious to do this work by hand, though. Let's write some code to explore Kaprekar's algorithm further!&lt;/p&gt;

&lt;h2&gt;
  
  
  From Concept to Code
&lt;/h2&gt;

&lt;p&gt;The core algorithm may be implemented in JavaScript as follows.&lt;/p&gt;

&lt;p&gt;First we convert a given number to a string &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart"&gt;padded with leading zeros&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;423&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0423&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we split the digits into an array so we can arrange them into our minimum and maximum numbers. The array operations are performed in-place, so a new array is created for each value:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally we use &lt;code&gt;join&lt;/code&gt; to convert each array back into a string and &lt;code&gt;parseInt&lt;/code&gt; to convert those back to numbers so we can subtract the values:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="mi"&gt;234&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="mi"&gt;4320&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  JavaScript Implementation
&lt;/h2&gt;

&lt;p&gt;The final code incorporates a &lt;code&gt;validate&lt;/code&gt; function to reject numbers without multiple digits and runs our algorithm automatically using a random four-digit number:&lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
  &lt;/code&gt;
  &lt;code&gt;
    
validate = function (num) {
  for (var i = 0; i &amp;lt; 10000; i += 1111) {
    if (num == i) {
      return false;
    }
  }
  return true;
}

kaprekar = function (num) {
  if (!validate(num)) {
    console.log("Invalid number " + num);
    return;
  }
  console.log(num);
  while (num != 6174) {
    var str = num.toString().padStart(4, '0');
    var max = parseInt(str.split('').sort().reverse().join(''));
    var min = parseInt(str.split('').sort().join(''));
    num = max - min;
    console.log(num);
  }
}

var n = Math.random() * 10000 | 0; // from https://stackoverflow.com/a/61696576
kaprekar(n);

  &lt;/code&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  But wait, there's more!
&lt;/h2&gt;

&lt;p&gt;Here is a variation of the program that generates a histogram of many iterations it takes to reach &lt;code&gt;6174&lt;/code&gt; for all four-digit numbers. &lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
  &lt;/code&gt;
  &lt;code&gt;
    
counts = {};

validate = function(num) {
  for (var i = 0; i &amp;lt; 10000; i += 1111) {
    if (num == i) {
      return false;
    }
  }
  return true;
}

kaprekar = function(num) {
  var count = 0;
  if (!validate(num)) {
    return;
  }
  while(num != 6174) {
    str = num.toString().padStart(4, '0');
    max = parseInt(str.split('').sort().reverse().join(''));
    min = parseInt(str.split('').sort().join(''));
    num = max - min;
    count++;
  }
  counts[count] = counts[count] || 0;
  counts[count]++;
}

for (var i = 1; i &amp;lt; 10000; i++) {
  kaprekar(i); 
}
console.log(counts);

  &lt;/code&gt;
&lt;/div&gt;


&lt;p&gt;Running this code you can see we reach &lt;code&gt;6174&lt;/code&gt; after at most seven iterations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;383&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;576&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1272&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1518&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1656&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2184&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And that's it! Hope you enjoyed this fun little tidbit. &lt;/p&gt;

&lt;p&gt;Please feel free to leave your thoughts in the comments ☀️ 😄 👍&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>math</category>
      <category>algorithms</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to use jQuery CSS selectors in vanilla JavaScript ?</title>
      <dc:creator>Justin Ethier</dc:creator>
      <pubDate>Fri, 06 May 2022 21:27:43 +0000</pubDate>
      <link>https://dev.to/justinethier/how-to-use-jquery-css-selectors-in-vanilla-javascript--4gel</link>
      <guid>https://dev.to/justinethier/how-to-use-jquery-css-selectors-in-vanilla-javascript--4gel</guid>
      <description>&lt;p&gt;One of the best features of jQuery is the use of CSS selectors to reference elements, EG: &lt;code&gt;$('#my-id')&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;How can I use selectors when writing vanilla JavaScript?&lt;/p&gt;

</description>
      <category>help</category>
    </item>
  </channel>
</rss>
