<?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: I Want To Learn Programming</title>
    <description>The latest articles on DEV Community by I Want To Learn Programming (@iwtlp).</description>
    <link>https://dev.to/iwtlp</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972025%2Fe29e6194-b687-42ba-947e-36f7f02185ad.png</url>
      <title>DEV Community: I Want To Learn Programming</title>
      <link>https://dev.to/iwtlp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iwtlp"/>
    <language>en</language>
    <item>
      <title>Code Challenge of the Day — First occurrence (leftmost) (medium)</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Mon, 29 Jun 2026 14:00:05 +0000</pubDate>
      <link>https://dev.to/iwtlp/code-challenge-of-the-day-first-occurrence-leftmost-medium-4l6m</link>
      <guid>https://dev.to/iwtlp/code-challenge-of-the-day-first-occurrence-leftmost-medium-4l6m</guid>
      <description>&lt;p&gt;Picks up where Binary search left off.&lt;/p&gt;

&lt;p&gt;You wrote binary search. Extend it: with duplicates, return the leftmost index of target, or -1.&lt;br&gt;
Write first_occurrence(nums, target).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_occurrence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Solve it interactively in your browser (no setup), check your answer instantly, and keep your daily streak going on IWTLP: &lt;a href="https://iwtlp.com/challenge" rel="noopener noreferrer"&gt;https://iwtlp.com/challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>challenge</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Build your own search engine, inverted index and TF-IDF</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Mon, 29 Jun 2026 14:00:03 +0000</pubDate>
      <link>https://dev.to/iwtlp/build-your-own-search-engine-inverted-index-and-tf-idf-1fam</link>
      <guid>https://dev.to/iwtlp/build-your-own-search-engine-inverted-index-and-tf-idf-1fam</guid>
      <description>&lt;p&gt;Type into a search box, get back the most relevant documents, instantly, out of millions. It feels like something only Google can do. But the engine behind ordinary full-text search, the thing inside Elasticsearch, Lucene, and your site's search bar, rests on two ideas you can build in about 30 lines: an &lt;strong&gt;inverted index&lt;/strong&gt; to find matching documents fast, and &lt;strong&gt;TF-IDF&lt;/strong&gt; to rank them by relevance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea: flip the data around
&lt;/h2&gt;

&lt;p&gt;The naive way to search is to scan every document for the query word. That's &lt;code&gt;O(documents × length)&lt;/code&gt;, hopeless at scale. The fix is to build the index &lt;em&gt;backwards&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A normal index maps document → its words. An &lt;strong&gt;inverted index&lt;/strong&gt; maps the other way: word → the documents that contain it (and how often). Now "find documents containing &lt;code&gt;python&lt;/code&gt;" is a single dictionary lookup instead of a scan. Flipping the mapping is the entire reason search is fast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;        &lt;span class="c1"&gt;# real engines also strip punctuation, stem, etc.
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# term -&amp;gt; {doc_id: term_frequency}
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;

&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python is a great language for data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search engines rank documents by relevance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python powers data science and search&lt;/span&gt;&lt;span class="sh"&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;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;     &lt;span class="c1"&gt;# {0: 1, 2: 1}  -&amp;gt; docs 0 and 2, once each
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;     &lt;span class="c1"&gt;# {1: 1, 2: 1}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One lookup gives you every document containing a term, plus the term frequency, which we'll need for ranking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The second idea: rank by relevance with TF-IDF
&lt;/h2&gt;

&lt;p&gt;Matching isn't enough, you need the &lt;em&gt;best&lt;/em&gt; matches first. TF-IDF scores how important a term is to a document with two intuitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TF (term frequency):&lt;/strong&gt; a document that uses the query word more is more about it. More mentions, higher score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDF (inverse document frequency):&lt;/strong&gt; a word that appears in &lt;em&gt;every&lt;/em&gt; document (like "the") tells you nothing, so it should count for little. A rare word that appears in few documents is highly discriminating, so it should count for a lot. IDF is &lt;code&gt;log(total_docs / docs_containing_term)&lt;/code&gt;, big for rare words, near zero for ubiquitous ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multiply them: a term scores high in a document when it appears often &lt;em&gt;there&lt;/em&gt; but rarely &lt;em&gt;overall&lt;/em&gt;. That's the insight that makes results feel relevant, it automatically downweights common filler and rewards distinctive matches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n_docs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;df&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;              &lt;span class="c1"&gt;# how many docs contain the term
&lt;/span&gt;        &lt;span class="n"&gt;idf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_docs&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;# rare terms -&amp;gt; larger idf
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;idf&lt;/span&gt;      &lt;span class="c1"&gt;# accumulate TF-IDF across query terms
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kv&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="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="c1"&gt;# docs 0 and 2 rank top: they match both query terms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;We only score documents in the index for the query terms.&lt;/strong&gt; Thanks to the inverted index, we never touch documents that don't match. The cost scales with how many docs contain your &lt;em&gt;words&lt;/em&gt;, not your whole corpus, the reason this is fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scores accumulate across query terms.&lt;/strong&gt; A document matching both "python" and "data" outranks one matching only one of them. Multi-word relevance falls right out of the sum.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  From this to a real engine
&lt;/h2&gt;

&lt;p&gt;This 30-line core is genuinely how production search starts. The rest is refinement, not new ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Better tokenization:&lt;/strong&gt; lowercasing, removing punctuation, &lt;em&gt;stemming&lt;/em&gt; ("running" → "run") so variants match, dropping stop words.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better ranking:&lt;/strong&gt; BM25, a tuned evolution of TF-IDF that handles document length and term saturation, this is what Elasticsearch/Lucene actually use by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phrase and boolean queries&lt;/strong&gt;, using the &lt;em&gt;positions&lt;/em&gt; of terms (store position lists in the index, not just counts).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale:&lt;/strong&gt; sharding the index across machines, the inverted-index structure is what makes that distribution possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of those sits on top of "word → documents" plus "score by TF-IDF." Even modern semantic search with &lt;a href="https://iwtlp.com/blog/vectors-are-a-data-type-now" rel="noopener noreferrer"&gt;vectors&lt;/a&gt; is usually &lt;em&gt;combined&lt;/em&gt; with this keyword index, not a replacement for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is worth building
&lt;/h2&gt;

&lt;p&gt;Search is one of those capabilities that looks like deep infrastructure and turns out to be two clean ideas: invert the mapping so lookups are instant, and score by TF-IDF so the best matches rise. Build it once and Elasticsearch stops being a black box, it's this, hardened and distributed.&lt;/p&gt;

&lt;p&gt;Taking it further, BM25, positional queries, stemming, and the bridge to embeddings, is exactly the path the &lt;a href="https://iwtlp.com/track/nlp-python" rel="noopener noreferrer"&gt;NLP&lt;/a&gt; track follows, building the search engine instead of configuring one.&lt;/p&gt;

</description>
      <category>search</category>
      <category>nlp</category>
      <category>tfidf</category>
      <category>python</category>
    </item>
    <item>
      <title>Code Challenge of the Day — Palindrome, ignoring case and noise (medium)</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Sun, 28 Jun 2026 14:00:09 +0000</pubDate>
      <link>https://dev.to/iwtlp/code-challenge-of-the-day-palindrome-ignoring-case-and-noise-medium-8p5</link>
      <guid>https://dev.to/iwtlp/code-challenge-of-the-day-palindrome-ignoring-case-and-noise-medium-8p5</guid>
      <description>&lt;p&gt;Picks up where Palindrome check left off.&lt;/p&gt;

&lt;p&gt;You checked simple palindromes. Now ignore case and any non-alphanumeric characters, then check.&lt;br&gt;
Write is_clean_palindrome(s).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_clean_palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Solve it interactively in your browser (no setup), check your answer instantly, and keep your daily streak going on IWTLP: &lt;a href="https://iwtlp.com/challenge" rel="noopener noreferrer"&gt;https://iwtlp.com/challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>challenge</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Simpson's paradox, and a detector for it in 20 lines</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Sun, 28 Jun 2026 14:00:04 +0000</pubDate>
      <link>https://dev.to/iwtlp/simpsons-paradox-and-a-detector-for-it-in-20-lines-pj0</link>
      <guid>https://dev.to/iwtlp/simpsons-paradox-and-a-detector-for-it-in-20-lines-pj0</guid>
      <description>&lt;p&gt;Here is a dataset that lies. Sixty-six people, each with two numbers: hours of exercise per week, and blood cholesterol. Fit a single straight line to all of them and the slope is positive: more exercise, more cholesterol. That is absurd, and it is also what the data says, until you split the points by age. Within every age band the slope is negative, the sane direction. Same points, opposite conclusion, depending only on whether you looked at the whole or the parts.&lt;/p&gt;

&lt;p&gt;This is Simpson's paradox, and it is not a curiosity. In 1973 it nearly turned into a lawsuit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The slope is two sums
&lt;/h2&gt;

&lt;p&gt;You do not need a stats library to see this happen. The slope of a least-squares line is the covariance of &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; divided by the variance of &lt;code&gt;x&lt;/code&gt;, and both are just sums:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;slope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cov&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mx&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;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cov&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it on everyone pooled together and you get &lt;code&gt;+12&lt;/code&gt;. Run it on each age band and every one comes back negative. Nothing is wrong with the math; the same function gives both answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why pooling flips the sign
&lt;/h2&gt;

&lt;p&gt;The reason is a clean identity. Total covariance decomposes into a within-group part and a between-group part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cov_total = (average within-group covariance) + (covariance of the group means)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The within-group term is the honest signal: inside a fixed age, more exercise tracks with less cholesterol, so it is negative. The between-group term measures where the groups &lt;em&gt;sit&lt;/em&gt;. Older people exercise more, because retirement, and older people also have higher cholesterol, so the group centroids climb to the right and upward together. That between-group covariance is large and positive, and when you pool, it swamps the within-group signal. The pooled line is mostly tracing the path through the group centroids, not the slope inside any group.&lt;/p&gt;

&lt;p&gt;Age is doing two jobs at once: it moves a point along the x-axis and along the y-axis. That is the definition of a confounder, a variable tied to both axes, and a confounder is exactly what it takes to reverse a trend.&lt;/p&gt;

&lt;h2&gt;
  
  
  A detector in twenty lines
&lt;/h2&gt;

&lt;p&gt;If the danger is that the pooled trend disagrees with every group, you can just check for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reverses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_of&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;ys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&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;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;pooled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;slope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;group_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;gx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;gy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&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;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;slope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gy&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;flipped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;pooled&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;flipped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pooled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feed it the exercise data grouped by age and it returns &lt;code&gt;True&lt;/code&gt;, with &lt;code&gt;pooled = +12&lt;/code&gt; and three negative group slopes. Before trusting any pooled trend, run this against your plausible confounders: age, region, device, customer tier, time period. If it fires, the aggregate is hiding something.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same trap in rates
&lt;/h2&gt;

&lt;p&gt;It is not only about regression lines. In 1973 the University of California, Berkeley looked like it was rejecting women from graduate school: across the university, men were admitted at about 44 percent and women at about 30. It looked like clear bias. But split the applicants by department and women were admitted at an equal or higher rate in four of the six largest departments. Women were applying in larger numbers to the more competitive departments, the ones with low admit rates for everyone. Department was the confounder, moving both who applied and the admit rate. The aggregate reversed the truth. Same paradox, counted in percentages instead of slopes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the detector is a smoke alarm, not a verdict
&lt;/h2&gt;

&lt;p&gt;Here is the part most write-ups skip, and the part that matters most. The detector tells you that a reversal exists. It does not tell you which view is correct. That is a causal question, not a statistical one, and the honest answer depends on what the grouping variable actually is.&lt;/p&gt;

&lt;p&gt;If the group is a genuine confounder that sits upstream of both variables, like age here, then the within-group slopes are the truth and the pooled slope is the artifact. But if you split on the wrong variable you make things worse. Condition on a collider, a variable that both &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; cause, and you can manufacture a paradox out of unrelated quantities. Condition on something that sits downstream of the treatment, a mediator, and you erase the very effect you were trying to measure. The math of &lt;code&gt;reverses()&lt;/code&gt; cannot tell these cases apart; they all look like a sign flip.&lt;/p&gt;

&lt;p&gt;So the rule is not "always trust the groups." It is "a reversal means stop and draw the causal arrows." The detector is the smoke alarm. The causal diagram is the investigation. If you want the formal version of all this, look up the d-separation rules for causal graphs; Simpson's paradox is what they were built to resolve.&lt;/p&gt;

&lt;p&gt;The toy is worth building anyway, because once you have watched the same &lt;code&gt;slope()&lt;/code&gt; function return &lt;code&gt;+12&lt;/code&gt; and a row of negatives on the same data, you stop trusting any single aggregate on sight. That instinct is most of what good data analysis is.&lt;/p&gt;

</description>
      <category>simpsonsparadox</category>
      <category>statistics</category>
      <category>confounding</category>
      <category>python</category>
    </item>
    <item>
      <title>Code Challenge of the Day — Count two-sum pairs (medium)</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Sat, 27 Jun 2026 14:00:09 +0000</pubDate>
      <link>https://dev.to/iwtlp/code-challenge-of-the-day-count-two-sum-pairs-medium-1jlo</link>
      <guid>https://dev.to/iwtlp/code-challenge-of-the-day-count-two-sum-pairs-medium-1jlo</guid>
      <description>&lt;p&gt;Picks up where Two-sum indices left off.&lt;/p&gt;

&lt;p&gt;Same setup as two-sum, but count how many index pairs (i&amp;lt;j) sum to target.&lt;br&gt;
Write count_pairs(nums, target).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;count_pairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Solve it interactively in your browser (no setup), check your answer instantly, and keep your daily streak going on IWTLP: &lt;a href="https://iwtlp.com/challenge" rel="noopener noreferrer"&gt;https://iwtlp.com/challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>challenge</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Rust's rewrite wave, why C is being replaced in the places that matter</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Sat, 27 Jun 2026 14:00:06 +0000</pubDate>
      <link>https://dev.to/iwtlp/rusts-rewrite-wave-why-c-is-being-replaced-in-the-places-that-matter-1683</link>
      <guid>https://dev.to/iwtlp/rusts-rewrite-wave-why-c-is-being-replaced-in-the-places-that-matter-1683</guid>
      <description>&lt;p&gt;In 2026 the Rust rewrite wave reached the load-bearing parts of computing: the Linux kernel ships Rust drivers, browsers and databases have Rust cores, and Rust runs in production infrastructure at Microsoft, Google, Amazon, and Cloudflare. Rust also tops developer surveys with an ~82% admiration rating, the most-loved language for years running. That combination, beloved &lt;em&gt;and&lt;/em&gt; being put in the most critical code, is unusual and worth understanding.&lt;/p&gt;

&lt;p&gt;The motivation is not fashion. It is one specific, measurable problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea: most critical-software bugs are memory bugs
&lt;/h2&gt;

&lt;p&gt;For decades the systems world ran on C and C++: fast, close to the metal, and trusting the programmer to manage memory by hand. The trouble is that humans are bad at it. Use-after-free, buffer overflows, dangling pointers, data races, these memory-safety bugs are not exotic. Studies from Microsoft and Google repeatedly found that &lt;strong&gt;roughly 70% of serious security vulnerabilities&lt;/strong&gt; in large C/C++ codebases are memory-safety issues.&lt;/p&gt;

&lt;p&gt;That is the number driving the rewrite. If you could eliminate that category of bug, you'd remove most of your security vulnerabilities at a stroke. Rust's entire reason to exist is to make those bugs &lt;em&gt;impossible to compile&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Rust gets safety without a garbage collector
&lt;/h2&gt;

&lt;p&gt;The usual way to get memory safety is a garbage collector (Java, Go, Python): a runtime that tracks and frees memory for you. But a GC adds overhead and unpredictable pauses, unacceptable in a kernel or a high-frequency trading path. That's why those domains stuck with C.&lt;/p&gt;

&lt;p&gt;Rust's breakthrough is getting memory safety &lt;strong&gt;at compile time, with no runtime cost&lt;/strong&gt;. Its &lt;a href="https://iwtlp.com/blog/the-borrow-checker-explained-by-fighting-it" rel="noopener noreferrer"&gt;borrow checker&lt;/a&gt; enforces ownership rules, one owner per value, and "shared XOR mutable" references, that make use-after-free and data races &lt;em&gt;compile errors&lt;/em&gt;. The checks happen during compilation and then vanish; the running program is as lean as C. You get C's performance and the safety of a managed language, without choosing between them. That "no GC, no memory bugs" combination is exactly what the critical-infrastructure crowd was waiting for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why now, and not five years ago
&lt;/h2&gt;

&lt;p&gt;Rust has been safe for a decade, so why the 2026 wave? Three things matured at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The ecosystem hit critical mass.&lt;/strong&gt; Production-grade libraries, Tokio (async), Axum (web), SQLx (databases), mean you can build real systems without reinventing everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The tooling and ergonomics improved.&lt;/strong&gt; Compile times for incremental builds dropped dramatically (from ~35s to ~8s on medium projects between 2024 and 2026), and the error messages became genuinely teacherly. The language got &lt;em&gt;approachable&lt;/em&gt;, which is what the admiration rating reflects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy pressure.&lt;/strong&gt; Government and industry security guidance began explicitly recommending memory-safe languages for new critical software. The 70% number became a mandate, not just a statistic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the rewrite wave is &lt;em&gt;not&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Worth being honest, because the hype overshoots:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It is not "rewrite everything in Rust."&lt;/strong&gt; The migration targets &lt;em&gt;new&lt;/em&gt; components and the highest-risk existing ones (parsers, network-facing code, kernel drivers). Vast amounts of working C will run for decades. A rewrite is expensive and risky; you do it where the safety payoff is largest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust is not always the right tool.&lt;/strong&gt; For a quick script, Python wins. For a simple network service where a GC pause is fine, Go's simplicity often wins. Rust's borrow checker is a real cost you pay for a real guarantee; it's worth it when the guarantee matters and overkill when it doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe Rust isn't &lt;em&gt;all&lt;/em&gt; Rust.&lt;/strong&gt; &lt;code&gt;unsafe&lt;/code&gt; blocks exist for the cases that need manual control (hardware, FFI), and bugs can still live there. The win is shrinking the unsafe surface to a small, auditable fraction.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this matters even if you never write Rust
&lt;/h2&gt;

&lt;p&gt;The rewrite wave is a signal about where the industry's pain actually is: not in writing code, but in writing &lt;em&gt;correct&lt;/em&gt; code that doesn't corrupt memory or ship vulnerabilities. Rust is the current best answer, but the underlying lesson is bigger, that moving the discovery of whole bug classes from runtime to compile time is enormously valuable, which is the same reason typed languages keep gaining ground.&lt;/p&gt;

&lt;p&gt;Understanding &lt;em&gt;why&lt;/em&gt; Rust is winning, the 70% number, the no-GC safety, the compile-time guarantee, tells you more than any syntax tutorial. And the only way to really feel it is to write Rust until the borrow checker stops fighting you and starts feeling like a safety net. That's the &lt;a href="https://iwtlp.com/track/rust" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; track, built ownership-first because that's the idea everything else hangs on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.techrepublic.com/article/news-tiobe-index-language-rankings/" rel="noopener noreferrer"&gt;TIOBE Index, June 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/zny10289/rust-in-2026-the-systems-language-that-finally-became-approachable-57ca"&gt;Rust in 2026: the systems language that finally became approachable — DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/news-insights/octoverse/what-the-fastest-growing-tools-reveal-about-how-software-is-being-built/" rel="noopener noreferrer"&gt;What the fastest-growing tools reveal — GitHub Octoverse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>systems</category>
      <category>memorysafety</category>
      <category>c</category>
    </item>
    <item>
      <title>Code Challenge of the Day — Clamp a value (easy)</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Fri, 26 Jun 2026 14:00:06 +0000</pubDate>
      <link>https://dev.to/iwtlp/code-challenge-of-the-day-clamp-a-value-easy-82j</link>
      <guid>https://dev.to/iwtlp/code-challenge-of-the-day-clamp-a-value-easy-82j</guid>
      <description>&lt;p&gt;Return x limited to the range [lo, hi].&lt;br&gt;
Write clamp(x, lo, hi).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Solve it interactively in your browser (no setup), check your answer instantly, and keep your daily streak going on IWTLP: &lt;a href="https://iwtlp.com/challenge" rel="noopener noreferrer"&gt;https://iwtlp.com/challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>challenge</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Gradient descent, explained by rolling downhill</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Fri, 26 Jun 2026 14:00:03 +0000</pubDate>
      <link>https://dev.to/iwtlp/gradient-descent-explained-by-rolling-downhill-5fkl</link>
      <guid>https://dev.to/iwtlp/gradient-descent-explained-by-rolling-downhill-5fkl</guid>
      <description>&lt;p&gt;Behind every trained model, the &lt;a href="https://iwtlp.com/blog/what-attention-really-is-by-coding-it" rel="noopener noreferrer"&gt;attention&lt;/a&gt; layers, the giant language models, the small on-device ones, is a single training algorithm: gradient descent. It sounds like calculus you'd rather forget, but the idea is a ball rolling downhill, and the code is about three lines. Build it once and "training a model" stops being mysterious.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea: follow the slope downhill
&lt;/h2&gt;

&lt;p&gt;Suppose you have a function that measures how &lt;em&gt;wrong&lt;/em&gt; your model is, the loss. Training means finding the inputs that make the loss as small as possible: the bottom of the valley. You can't see the whole landscape, but at any point you can feel the &lt;strong&gt;slope&lt;/strong&gt; under your feet. So you take a small step in the downhill direction, and repeat. Roll downhill, step by step, until you reach the bottom.&lt;/p&gt;

&lt;p&gt;The slope is the &lt;strong&gt;gradient&lt;/strong&gt; (the derivative): it points in the direction the function increases fastest. So to go &lt;em&gt;down&lt;/em&gt;, you step in the &lt;em&gt;opposite&lt;/em&gt; direction of the gradient. That's the whole algorithm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimize a parabola
&lt;/h2&gt;

&lt;p&gt;Take &lt;code&gt;f(x) = (x - 3)²&lt;/code&gt;. Its lowest point is obviously at &lt;code&gt;x = 3&lt;/code&gt;. Its slope is &lt;code&gt;f'(x) = 2(x - 3)&lt;/code&gt;. Gradient descent finds the minimum without knowing the answer in advance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gradient_descent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# step opposite the slope
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;gradient_descent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# -&amp;gt; ~3.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start at 0, and each step nudges &lt;code&gt;x&lt;/code&gt; toward 3, the bottom of the bowl. That single line, &lt;code&gt;x = x - lr * grad(x)&lt;/code&gt;, is gradient descent. Everything else in machine learning is computing &lt;code&gt;grad&lt;/code&gt; for more complicated functions.&lt;/p&gt;

&lt;p&gt;Two details that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The learning rate &lt;code&gt;lr&lt;/code&gt;&lt;/strong&gt; is your step size. Too small and it crawls; too large and it overshoots the bottom and can bounce out to infinity. Tuning it is most of the practical art.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You step &lt;em&gt;against&lt;/em&gt; the gradient.&lt;/strong&gt; The minus sign is the whole point. Flip it and you'd climb the hill, maximizing the loss, which is exactly backwards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fit a line to data
&lt;/h2&gt;

&lt;p&gt;Now the real thing. Given points, find the line &lt;code&gt;y = mx + b&lt;/code&gt; that best fits them. "Best" means smallest mean squared error. The loss is &lt;code&gt;mean((mx + b − y)²)&lt;/code&gt;, and its gradients with respect to &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are standard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fit_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;errs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;   &lt;span class="c1"&gt;# prediction minus truth
&lt;/span&gt;        &lt;span class="n"&gt;dm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# slope wrt m
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                              &lt;span class="c1"&gt;# slope wrt b
&lt;/span&gt;        &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dm&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;ys&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;          &lt;span class="c1"&gt;# perfectly y = 2x
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fit_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;        &lt;span class="c1"&gt;# -&amp;gt; (~2.0, ~0.0)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No formula for the answer, no library. We started with a flat line (&lt;code&gt;m=0, b=0&lt;/code&gt;), measured how wrong it was, and rolled downhill in &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; until it matched. That is linear regression, &lt;em&gt;trained&lt;/em&gt;, and it is the same loop that trains a neural network, just with millions of parameters instead of two.&lt;/p&gt;

&lt;h2&gt;
  
  
  From two parameters to a billion
&lt;/h2&gt;

&lt;p&gt;A neural network is the exact same idea at scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model has millions or billions of parameters instead of &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The loss measures how wrong its predictions are.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backpropagation&lt;/strong&gt; is just an efficient way to compute the gradient of the loss with respect to &lt;em&gt;every&lt;/em&gt; parameter at once (we build it from scratch in &lt;a href="https://iwtlp.com/blog/backpropagation-explained-by-coding-it" rel="noopener noreferrer"&gt;backpropagation explained by coding it&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Then the same update runs: &lt;code&gt;param -= lr * grad&lt;/code&gt;, for every parameter, over and over.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. "Training GPT" and "fitting a line" are the same algorithm; only the number of parameters and the way you compute the gradient differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is worth building
&lt;/h2&gt;

&lt;p&gt;Gradient descent is the one algorithm that connects a textbook parabola to the largest models on Earth. Once you've watched &lt;code&gt;x = x - lr * grad(x)&lt;/code&gt; walk to the bottom of a bowl, the whole field reorganizes around it: a model is a function with parameters, a loss says how wrong it is, and training is rolling those parameters downhill. The learning rate, overfitting, why training "diverges", all of it makes sense from this picture.&lt;/p&gt;

&lt;p&gt;If you want to build outward from here, backprop, real networks, the optimizers that improve on plain descent, that path is the &lt;a href="https://iwtlp.com/track/ai-python" rel="noopener noreferrer"&gt;AI&lt;/a&gt; track, where you train the thing from the gradient up instead of importing &lt;code&gt;.fit()&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>optimization</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>Code Challenge of the Day — Letter grade (easy)</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Thu, 25 Jun 2026 14:00:06 +0000</pubDate>
      <link>https://dev.to/iwtlp/code-challenge-of-the-day-letter-grade-easy-5e16</link>
      <guid>https://dev.to/iwtlp/code-challenge-of-the-day-letter-grade-easy-5e16</guid>
      <description>&lt;p&gt;Return 'A' for &amp;gt;=90, 'B' for &amp;gt;=80, 'C' for &amp;gt;=70, 'D' for &amp;gt;=60, else 'F'.&lt;br&gt;
Write grade(score).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;grade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Solve it interactively in your browser (no setup), check your answer instantly, and keep your daily streak going on IWTLP: &lt;a href="https://iwtlp.com/challenge" rel="noopener noreferrer"&gt;https://iwtlp.com/challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>challenge</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Build your own shell, and learn how every program gets started</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Thu, 25 Jun 2026 14:00:03 +0000</pubDate>
      <link>https://dev.to/iwtlp/build-your-own-shell-and-learn-how-every-program-gets-started-2o1n</link>
      <guid>https://dev.to/iwtlp/build-your-own-shell-and-learn-how-every-program-gets-started-2o1n</guid>
      <description>&lt;p&gt;You type &lt;code&gt;ls&lt;/code&gt;, press enter, and a program runs. The shell that made that happen feels like deep operating-system magic. It isn't. A real, working shell, one that can run any program on your system, is about 30 lines of C, and writing it teaches you the single most important pattern in operating systems: how one program starts another.&lt;/p&gt;

&lt;p&gt;That pattern is three system calls: &lt;strong&gt;fork&lt;/strong&gt;, &lt;strong&gt;exec&lt;/strong&gt;, and &lt;strong&gt;wait&lt;/strong&gt;. Every program you have ever launched, from your editor to your browser, was started this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea: fork then exec
&lt;/h2&gt;

&lt;p&gt;To run a program, a Unix shell does something that sounds strange the first time: it &lt;strong&gt;clones itself&lt;/strong&gt;, and then the clone &lt;strong&gt;replaces itself&lt;/strong&gt; with the program you asked for.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fork()&lt;/code&gt; creates a near-identical copy of the current process (the child). Now there are two processes running the same code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exec()&lt;/code&gt; replaces the calling process's memory with a new program. The child stops being a copy of the shell and &lt;em&gt;becomes&lt;/em&gt; &lt;code&gt;ls&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wait()&lt;/code&gt; lets the parent (the shell) pause until the child finishes, so it can prompt you again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clone, transform, wait. That separation, fork to make a process, exec to choose what it runs, is the deepest idea in how operating systems launch programs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop
&lt;/h2&gt;

&lt;p&gt;A shell is a read-eval-print loop: read a line, run it, repeat.&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="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/wait.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1024&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="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="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;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;fgets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// Ctrl-D / EOF: exit&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;strcspn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&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="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// strip the newline&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;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                 &lt;span class="c1"&gt;// empty line&lt;/span&gt;

        &lt;span class="c1"&gt;// split the line into words: args[0]=command, rest=arguments&lt;/span&gt;
        &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&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="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strtok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;tok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;tok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strtok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&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;tok&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                                &lt;span class="c1"&gt;// execvp needs a NULL terminator&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;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"exit"&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// a builtin, handled by the shell itself&lt;/span&gt;

        &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&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="mi"&gt;0&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;Two details that matter already:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;args&lt;/code&gt; must end in &lt;code&gt;NULL&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;execvp&lt;/code&gt; reads the argument list until it hits a NULL pointer. Forget it and you get garbage or a crash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;exit&lt;/code&gt; is a builtin.&lt;/strong&gt; It can't be a separate program, because a child process exiting wouldn't end the shell. Builtins are commands the shell must run &lt;em&gt;itself&lt;/em&gt;, the same reason &lt;code&gt;cd&lt;/code&gt; has to be a builtin (a child can't change the parent's directory).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The heart: fork, exec, wait
&lt;/h2&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;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pid_t&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                 &lt;span class="c1"&gt;// clone this process&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;pid&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// --- child: become the requested program ---&lt;/span&gt;
        &lt;span class="n"&gt;execvp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&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;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// replaces this process; searches PATH for args[0]&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exec"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 &lt;span class="c1"&gt;// only runs if exec FAILED (e.g. command not found)&lt;/span&gt;
        &lt;span class="n"&gt;_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;127&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// --- parent (the shell): wait for the child to finish ---&lt;/span&gt;
        &lt;span class="n"&gt;waitpid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fork"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 &lt;span class="c1"&gt;// fork itself failed&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;This is the whole engine. Compile it (&lt;code&gt;cc shell.c -o myshell&lt;/code&gt;), run &lt;code&gt;./myshell&lt;/code&gt;, and you have a prompt that executes &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;echo hello&lt;/code&gt;, &lt;code&gt;cat file.txt&lt;/code&gt;, any program on your &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Three details that matter, and they are the entire concept:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;fork()&lt;/code&gt; returns twice.&lt;/strong&gt; Once in the parent (returning the child's PID, a positive number) and once in the child (returning 0). That single return value is how each process knows which one it is. This is the line that surprises everyone the first time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The code after &lt;code&gt;execvp&lt;/code&gt; only runs on failure.&lt;/strong&gt; A successful &lt;code&gt;exec&lt;/code&gt; &lt;em&gt;replaces&lt;/em&gt; the process, so there is no "after." Reaching &lt;code&gt;perror("exec")&lt;/code&gt; means the command wasn't found, which is exactly how your real shell prints "command not found."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;execvp&lt;/code&gt; searches &lt;code&gt;PATH&lt;/code&gt; for you&lt;/strong&gt; (the &lt;code&gt;p&lt;/code&gt;) and takes a vector of arguments (the &lt;code&gt;v&lt;/code&gt;). That is why you can type &lt;code&gt;ls&lt;/code&gt; instead of &lt;code&gt;/bin/ls&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you just built, and where it goes
&lt;/h2&gt;

&lt;p&gt;You have a real shell. The features you use every day are extensions of this core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipes&lt;/strong&gt; (&lt;code&gt;ls | grep x&lt;/code&gt;): create a &lt;code&gt;pipe()&lt;/code&gt;, fork two children, wire one's stdout to the other's stdin with &lt;code&gt;dup2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirection&lt;/strong&gt; (&lt;code&gt;&amp;gt; file&lt;/code&gt;): before &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;open&lt;/code&gt; the file and &lt;code&gt;dup2&lt;/code&gt; it onto stdout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background jobs&lt;/strong&gt; (&lt;code&gt;&amp;amp;&lt;/code&gt;): just don't &lt;code&gt;wait&lt;/code&gt; for the child.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signals&lt;/strong&gt; (Ctrl-C): handle &lt;code&gt;SIGINT&lt;/code&gt; so it interrupts the child, not the shell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of those is a small addition around the same fork/exec/wait skeleton. The terminal stops being magic once you've written the loop that launches a process, because that loop is, quite literally, how your operating system runs everything.&lt;/p&gt;

&lt;p&gt;If you want to build the rest, pipes, job control, signals, a real mini-shell, that is one of the projects in the &lt;a href="https://iwtlp.com/track/os-c" rel="noopener noreferrer"&gt;operating systems&lt;/a&gt; track, where you build the internals instead of just using them.&lt;/p&gt;

</description>
      <category>c</category>
      <category>shell</category>
      <category>operatingsystems</category>
      <category>unix</category>
    </item>
    <item>
      <title>Code Challenge of the Day — Decode ways (hard)</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Wed, 24 Jun 2026 14:00:07 +0000</pubDate>
      <link>https://dev.to/iwtlp/code-challenge-of-the-day-decode-ways-hard-29m6</link>
      <guid>https://dev.to/iwtlp/code-challenge-of-the-day-decode-ways-hard-29m6</guid>
      <description>&lt;p&gt;A digit string maps to letters (1-26). Return the number of ways to decode it.&lt;br&gt;
Write decode_ways(s).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decode_ways&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Solve it interactively in your browser (no setup), check your answer instantly, and keep your daily streak going on IWTLP: &lt;a href="https://iwtlp.com/challenge" rel="noopener noreferrer"&gt;https://iwtlp.com/challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>challenge</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Build your own bytecode VM, and see how languages really run</title>
      <dc:creator>I Want To Learn Programming</dc:creator>
      <pubDate>Wed, 24 Jun 2026 14:00:04 +0000</pubDate>
      <link>https://dev.to/iwtlp/build-your-own-bytecode-vm-and-see-how-languages-really-run-5cnf</link>
      <guid>https://dev.to/iwtlp/build-your-own-bytecode-vm-and-see-how-languages-really-run-5cnf</guid>
      <description>&lt;p&gt;When you run a Python file, Python does not execute your text. It first compiles it to &lt;strong&gt;bytecode&lt;/strong&gt;, a compact list of simple instructions, and then runs that bytecode on a &lt;strong&gt;virtual machine&lt;/strong&gt;. Java does the same (the JVM), so does C# (the CLR). "Virtual machine" sounds like a deep systems topic, but the core of a bytecode VM is almost embarrassingly small: a loop that reads instructions and pushes and pops a stack.&lt;/p&gt;

&lt;p&gt;Build one and the phrase "compiles to bytecode" stops being mysterious. We will write a VM in about 30 lines, then a tiny compiler that turns an expression into bytecode for it to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea: a stack machine
&lt;/h2&gt;

&lt;p&gt;Most bytecode VMs are &lt;strong&gt;stack machines&lt;/strong&gt;. There are no variables in the engine itself, just a stack and a handful of instructions that manipulate it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PUSH x&lt;/code&gt; puts a value on the stack.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ADD&lt;/code&gt; pops the top two, pushes their sum.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MUL&lt;/code&gt; pops the top two, pushes their product.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PRINT&lt;/code&gt; shows the top of the stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To compute &lt;code&gt;(2 + 3) * 4&lt;/code&gt;, you push 2, push 3, add (stack now has 5), push 4, multiply (stack now has 20). The expression became a flat list of stack operations. That flattening is the whole trick, and it is why bytecode is fast: each instruction is a tiny, fixed operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The VM: a loop over instructions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUSH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ADD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&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;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&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;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MUL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&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;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&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;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&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;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&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;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PRINT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&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="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown op &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a working virtual machine. Run our example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUSH&lt;/span&gt;&lt;span class="sh"&gt;"&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="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUSH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ADD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUSH&lt;/span&gt;&lt;span class="sh"&gt;"&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="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MUL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PRINT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,)])&lt;/span&gt;
&lt;span class="c1"&gt;# prints 20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order matters for non-commutative ops.&lt;/strong&gt; In &lt;code&gt;SUB&lt;/code&gt;, we pop &lt;code&gt;b&lt;/code&gt; then &lt;code&gt;a&lt;/code&gt; and compute &lt;code&gt;a - b&lt;/code&gt;, because &lt;code&gt;a&lt;/code&gt; was pushed first and sits &lt;em&gt;below&lt;/em&gt; &lt;code&gt;b&lt;/code&gt;. Get this backward and &lt;code&gt;5 - 3&lt;/code&gt; becomes &lt;code&gt;-2&lt;/code&gt;. The stack's last-in-first-out order is the whole reason the compiler must emit operands before operators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The VM is dumb on purpose.&lt;/strong&gt; It has no idea what an expression is; it just executes tiny steps. All the cleverness lives in whatever &lt;em&gt;produces&lt;/em&gt; the bytecode. That separation, smart compiler, simple VM, is exactly how real language runtimes are built.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The compiler: from a tree to bytecode
&lt;/h2&gt;

&lt;p&gt;Nobody writes bytecode by hand. A compiler turns a parsed expression (an abstract syntax tree) into it. Represent the tree as nested tuples, and compile it with a post-order walk, children first, then the operator, which is precisely the push-operands-then-operate order the stack needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compile_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUSH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;                 &lt;span class="c1"&gt;# e.g. ("+", 2, ("*", 3, 4))
&lt;/span&gt;    &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compile_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;compile_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ADD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MUL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,)}[&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;

&lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&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="mi"&gt;3&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="c1"&gt;# (2 + 3) * 4
&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compile_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PRINT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,)]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# [('PUSH', 2), ('PUSH', 3), ('ADD',), ('PUSH', 4), ('MUL',), ('PRINT',)]
&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                              &lt;span class="c1"&gt;# 20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The recursion mirrors the tree, and because it emits children before their operator, the bytecode comes out in exactly the order the stack machine wants. This is the same shape as the &lt;a href="https://iwtlp.com/blog/build-your-own-json-parser" rel="noopener noreferrer"&gt;JSON parser's&lt;/a&gt; recursion, one function walking a recursive structure, applied to code generation instead of parsing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a VM at all?
&lt;/h2&gt;

&lt;p&gt;Why not just walk the tree and evaluate it directly? Three reasons, and they are why real languages bother:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed.&lt;/strong&gt; A flat array of simple instructions is far faster to execute repeatedly than re-walking a tree of objects. This is why CPython compiles to bytecode once and runs it many times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability.&lt;/strong&gt; Bytecode is the same regardless of CPU. Compile once, run the VM anywhere, which is Java's entire "write once, run anywhere" promise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A clean seam.&lt;/strong&gt; The compiler and the runtime are decoupled, so you can optimize the bytecode, or even JIT-compile it to machine code later, without touching the language's front end.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you just built
&lt;/h2&gt;

&lt;p&gt;A stack, a loop, and a recursive compiler is the heart of how Python, Java, and C# actually run. Add instructions and you grow a real language: &lt;code&gt;LOAD&lt;/code&gt;/&lt;code&gt;STORE&lt;/code&gt; for variables, &lt;code&gt;JUMP&lt;/code&gt;/&lt;code&gt;JUMP_IF_FALSE&lt;/code&gt; for control flow, &lt;code&gt;CALL&lt;/code&gt;/&lt;code&gt;RETURN&lt;/code&gt; for functions. Each is a few more lines in the same loop. The fearsome "virtual machine" is just this, scaled up.&lt;/p&gt;

&lt;p&gt;If you want to take it all the way, from source text to tokens to a tree to bytecode to a running language, that is exactly the arc the &lt;a href="https://iwtlp.com/track/compilers-python" rel="noopener noreferrer"&gt;compilers&lt;/a&gt; track walks, and it starts with a loop over a stack just like this one.&lt;/p&gt;

</description>
      <category>compilers</category>
      <category>bytecode</category>
      <category>vm</category>
      <category>python</category>
    </item>
  </channel>
</rss>
