<?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: Diego Crespo</title>
    <description>The latest articles on DEV Community by Diego Crespo (@deusinmachina).</description>
    <link>https://dev.to/deusinmachina</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1093034%2Ffc9cd897-9505-4fdb-838e-6de26bd06032.png</url>
      <title>DEV Community: Diego Crespo</title>
      <link>https://dev.to/deusinmachina</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/deusinmachina"/>
    <language>en</language>
    <item>
      <title>The Story of Nel</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Fri, 29 Nov 2024 03:18:36 +0000</pubDate>
      <link>https://dev.to/deusinmachina/the-story-of-nel-eab</link>
      <guid>https://dev.to/deusinmachina/the-story-of-nel-eab</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Happy 🦃 Day! I hope everyone has a wonderful day&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Real Programmers code in the terminal.&lt;/p&gt;

&lt;p&gt;Maybe they dabble in slick IDEs now, in this decadent era of AI assistants, auto completion, and "intelligent" debuggers. But back in the good old days, when the term "cloud" referred to the weather and not where you stored your code, Real Programmers wrote in plain text editors. Not Visual Studio Code. Not even Helix or Fleet. Just GNU Emacs and Screen.&lt;/p&gt;

&lt;p&gt;Lest a whole new generation of developers grow up in ignorance of this glorious past, I feel duty bound to describe, as best I can through the generation gap, how a Real Programmer writes code. I'll call her Nel, because that's her name.&lt;/p&gt;

&lt;p&gt;I first met Nel when I joined a startup aiming to disrupt the world with yet another social app. The team was young, vibrant, and glued to their screens, eyes darting between Stack Overflow tabs and AI generated code snippets. Then there was Nel, a quiet figure hunched over a terminal window, typing furiously.&lt;/p&gt;

&lt;p&gt;Nel didn't approve of AI assistants.&lt;/p&gt;

&lt;p&gt;"If a programmer can't write code without an autocomplete," she said, "what good are they?"&lt;/p&gt;

&lt;p&gt;Nel had written, using nothing but Emacs and her wits, the most critical module our company had. The real time data processor that kept everything running smoothly. It was a marvel. While the rest of us wrestled with dependency hell and cursed the day JavaScript was invented, Nel's code hummed along with these things called static types that, she said, were all the documentation she needed.&lt;/p&gt;

&lt;p&gt;One day, disaster struck. An outage in us-east-1 left us disconnected from our beloved cloud services. Panic ensued. Without Stack Overflow, AI help, or even our code repositories, we were paralyzed. Features needed fixing, bugs needed squashing, and deadlines loomed ominously.&lt;/p&gt;

&lt;p&gt;All except Nel were in despair.&lt;/p&gt;

&lt;p&gt;"How can we code without the internet?" someone wailed.&lt;/p&gt;

&lt;p&gt;"I've reached my 2-hour monthly in office quota anyway. Message me on Microsoft Teams when everything is back up," said another.&lt;/p&gt;

&lt;p&gt;Nel looked up from her terminal, a faint smile playing on her lips.&lt;/p&gt;

&lt;p&gt;"Maybe we can, you know, stay here and write code," she suggested.&lt;/p&gt;

&lt;p&gt;"Without documentation? Without Google? Impossible!"&lt;/p&gt;

&lt;p&gt;Nel shrugged and returned to her screen. Curiosity got the better of me, and I wandered over to see what she was doing. Lines of code scrolled past at an impossible speed. Functions, classes, even the occasional comment, all appearing as if by magic. She wasn't even using a mouse or trackpad.&lt;/p&gt;

&lt;p&gt;"Are you... writing a new feature?" I asked, incredulous.&lt;/p&gt;

&lt;p&gt;"Fixing the data parser," she replied without looking up.&lt;/p&gt;

&lt;p&gt;"From memory?"&lt;/p&gt;

&lt;p&gt;She nodded.&lt;/p&gt;

&lt;p&gt;"But how do you remember the syntax? The APIs? Don't you need to look up anything?"&lt;/p&gt;

&lt;p&gt;Nel chuckled softly. "I've been coding in this language longer than most of you have been alive. Muscle memory, I suppose."&lt;/p&gt;

&lt;p&gt;I watched in awe as she deftly wrote a for loop, complete with iterator variables and proper scope handling, all without a single reference. It was as if I'd witnessed a unicorn.&lt;/p&gt;

&lt;p&gt;"Could you help me with a for loop?" I asked sheepishly.&lt;/p&gt;

&lt;p&gt;She paused and turned to face me fully for the first time.&lt;/p&gt;

&lt;p&gt;"Sure," she said, gesturing for me to sit. "What are you trying to do?"&lt;/p&gt;

&lt;p&gt;I explained the problem, expecting her to whip out her phone to search for an answer. Instead, she grabbed a notepad and sketched out the logic, walking me through each step.&lt;/p&gt;

&lt;p&gt;"See? No need for the internet. Just think through the problem," she said.&lt;/p&gt;

&lt;p&gt;She laughed as I gawked.&lt;/p&gt;

&lt;p&gt;"I used to have to do stuff like this on whiteboards for interviews," She smiled while shaking her head.&lt;/p&gt;

&lt;p&gt;Word spread through the office. One by one, team members approached Nel, seeking guidance. She became an impromptu mentor, her desk a shrine to the lost art of independent thinking.&lt;/p&gt;

&lt;p&gt;Meanwhile, the managers were in a frenzy. Deadlines were at risk! Productivity was plummeting! They called an emergency all hands.&lt;/p&gt;

&lt;p&gt;"We need solutions, people!" the CTO barked. "How can we work without our tools?"&lt;/p&gt;

&lt;p&gt;Nel stood up.&lt;/p&gt;

&lt;p&gt;"Perhaps we've become too reliant on them," she said calmly. "Maybe it's time we trusted our own abilities."&lt;/p&gt;

&lt;p&gt;Silence fell. The idea was radical, almost heretical.&lt;/p&gt;

&lt;p&gt;"But how will we manage without AI suggestions? Without code linters? Without..."&lt;/p&gt;

&lt;p&gt;"By programming," Nel reiterated, "by understanding our code, not just piecing together fragments from the internet."&lt;/p&gt;

&lt;p&gt;An idea sparked in Nel. "We could deploy the app on premises", "Mark has a 64-core 7.5GHz laptop with 256GB of Ram and two 10TB NVME drives. If we turned off all of the startup and electron apps we'd be able to run the entire thing locally."&lt;/p&gt;

&lt;p&gt;Eyes turned to Mark, who nodded slowly. "It just might be possible. We have as many employees here as we have users so it would be a good test of the app"&lt;/p&gt;

&lt;p&gt;The CTO considered this. "Can we set it up quickly?"&lt;/p&gt;

&lt;p&gt;"Absolutely," Nel interjected. "It might even run better than in the cloud."&lt;/p&gt;

&lt;p&gt;Emboldened, we set up the on premise deployment. With Nel's guidance, the process was smooth. We bypassed the cloud entirely, running everything locally.&lt;/p&gt;

&lt;p&gt;Her words stirred something in us. Emboldened, we returned to our desks. The hum of conversation was replaced by the clatter of keyboards. Slowly, code began to take shape...not copied, not generated, but crafted. Whenever we had issues, we would physically walk over and discuss them with our teammates. Questions that would be left unread for hours before a response was finally given, were answered in a matter of seconds.&lt;/p&gt;

&lt;p&gt;By the time the internet was restored, it had been 6 hours, the most I've ever worked without distractedly scrolling through short form video. We had accomplished more in those disconnected hours than we had in months.&lt;/p&gt;

&lt;p&gt;The CTO called another all hands, praising the team's resilience. They gushed about how much VC money we would be able to raise from all the featuers we had developed. But we knew who deserved the real credit.&lt;/p&gt;

&lt;p&gt;Nel's approach had sparked a revival of genius level programming. Developers started challenging themselves to code without immediately resorting to Google. Pair programming sessions became the norm, fostering collaboration and learning. People even began reading manuals. Not everyone could hack it though, but they eventually found their way into middle management positions.&lt;/p&gt;

&lt;p&gt;I asked Nel one day why she preferred Emacs over the myriad of sophisticated tools available.&lt;/p&gt;

&lt;p&gt;"Because it does exactly what I need...no more, no less," she replied. "It's just me and the code."&lt;/p&gt;

&lt;p&gt;I haven't kept in touch with Nel since she moved on to greener pastures...or perhaps terminals. But I like to think she's out there somewhere, still coding in Emacs, still eschewing the trappings of modern development.&lt;/p&gt;

&lt;p&gt;In any event, I was impressed enough that I've started relying less on AI assistants and more on my own understanding. And while I may never reach Nel's level of mastery, I still use VS Code after all, I did download the Vim Emulation plugin. I think I might do a lunch and learn once I finally master hjkl.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For those who don’t know this is a parody of The brilliant Story of Mel if you’ve never read it I highly recommend it!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/" rel="noopener noreferrer"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>satire</category>
    </item>
    <item>
      <title>Coding without braces: An alternate C Syntax</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Thu, 10 Oct 2024 13:24:25 +0000</pubDate>
      <link>https://dev.to/deusinmachina/coding-without-braces-an-alternate-c-syntax-4oj0</link>
      <guid>https://dev.to/deusinmachina/coding-without-braces-an-alternate-c-syntax-4oj0</guid>
      <description>&lt;p&gt;I recently stumbled upon an interesting piece of C language trivia that underscores how different computers were when C was first created. Specifically, C allows the use of digraphs (two letter combinations that represent a single letter) like &lt;code&gt;&amp;lt;%&lt;/code&gt; and &lt;code&gt;%&amp;gt;&lt;/code&gt; as alternatives of &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; and &lt;code&gt;&amp;lt;:&lt;/code&gt; and &lt;code&gt;:&amp;gt;&lt;/code&gt; as substitutes for &lt;code&gt;[&lt;/code&gt; and &lt;code&gt;]&lt;/code&gt;. The purpose of this was to provide an alternate syntax to support keyboards and character sets where braces and brackets were not available. The &lt;a href="https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Digraphs.html" rel="noopener noreferrer"&gt;Gnu C Language manual&lt;/a&gt; mentions these digraphs as well as &lt;code&gt;%:&lt;/code&gt; as an alternative to &lt;code&gt;#&lt;/code&gt;. Since nothing on the internet can be trusted anymore I wrote a simple program and compiled it to verify the claims.&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;
&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="o"&gt;&amp;lt;%&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;"Hello, World!&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;:&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;%&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="o"&gt;%&amp;gt;&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;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;%&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;"%d&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="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="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="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And lo and behold (don't take my word for it) it worked! While it's hard to imagine a keyboard without these symbols today, and I might be showing my ignorance of international keyboards here, I'm glad someone thought to include these alternatives.&lt;/p&gt;

&lt;p&gt;But if the &lt;a href="https://en.cppreference.com/w/c/language/operator_alternative" rel="noopener noreferrer"&gt;cpp reference&lt;/a&gt; is anything to go by there is is an expecation that all keyboards must have &lt;code&gt;?&lt;/code&gt;,&lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt; as there is an even more verbose version of this behavior in the form of trigraphs, which allow a three character sequence alternative instead of two. Examples include &lt;code&gt;??&amp;lt;&lt;/code&gt; for &lt;code&gt;{&lt;/code&gt; and  &lt;code&gt;??)&lt;/code&gt; for &lt;code&gt;]&lt;/code&gt; but there are many more which can be viewed &lt;a href="https://en.cppreference.com/w/c/language/operator_alternative#:~:text=Demonstrates%20alternative%20operator" rel="noopener noreferrer"&gt;in the cpp reference&lt;/a&gt;. While tripgrahs appear to be going away in C23, I have no doubt people have abused these as well as digraphs in code obfuscation competitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; a &lt;a href="https://mastodon.social/deck/@DiegoCrespo" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, and &lt;a href="https://www.threads.net/@deusinmachinablog" rel="noopener noreferrer"&gt;Threads&lt;/a&gt; if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/" rel="noopener noreferrer"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>programming</category>
      <category>c</category>
      <category>trivia</category>
    </item>
    <item>
      <title>Learning to use Docker</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Thu, 21 Mar 2024 12:53:12 +0000</pubDate>
      <link>https://dev.to/deusinmachina/learning-to-use-docker-5gej</link>
      <guid>https://dev.to/deusinmachina/learning-to-use-docker-5gej</guid>
      <description>&lt;p&gt;Docker was released 13 years ago and has quickly become a mainstay in the programming community. At first I avoided it, considering it too complex, intimidating, and a waste of time for small projects. But Docker is not any of those things. Sure, wrapping a complex project with a Docker bowtie can be challenging, but that's because non trivial projects usually require non trivial solutions. The benefits you get once this is accomplished though, is immense. But before we get to that, let's start simple. What is Docker? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Docker is a technology that helps you package and run your software applications in a consistent and efficient way, regardless of the computing environment they're running on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This package is typically called a Docker Image. The running instance of an Image is called a Docker Container. You can think of a Docker Image like a programming language and technology agnostic version of a C# or Java project, or a Python virtual environment. In those examples, the language settings and all of the packages that you install are only for that specific project/language you are working on.&lt;/p&gt;

&lt;p&gt;If others want to collaborate on the project, they will need to have the same settings and packages as you. For example, if you have a Python virtual environment you can run &lt;code&gt;pip freeze &amp;gt; requirements.txt&lt;/code&gt; to get the list of packages your project needs, then pass along the txt file to someone else who can then run &lt;code&gt;pip install -r requirements.txt&lt;/code&gt; to download the same packages. But what if the person trying to install the dependencies for your project has a different version of Python than you? They may run into dependency issues, due to functions being deprecated, or behavior being changed as a library matures. Docker avoids this problem.&lt;/p&gt;

&lt;p&gt;But there are more than just dependency conflicts that can doom a project. Sometimes projects require more than what the standard library, or 3rd party package ecosystem can provide.&lt;/p&gt;

&lt;p&gt;Let’s say you want to do OCR on some pdfs. You might decide to use &lt;code&gt;pytesseract&lt;/code&gt;. In the installation instructions it says that you need &lt;code&gt;Google Tesseract OCR&lt;/code&gt;, as &lt;code&gt;pytesseract&lt;/code&gt; is a wrapper over it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Install Google Tesseract OCR (additional info how to install the engine on Linux, Mac OSX and Windows). You must be able to invoke the tesseract command as tesseract. If this isn’t the case, for example because tesseract isn’t in your PATH, you will have to change the “tesseract_cmd” variable pytesseract.pytesseract.tesseract_cmd. Under Debian/Ubuntu you can use the package tesseract-ocr. For Mac OS users. please install homebrew package tesseract.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately &lt;code&gt;Tesseract&lt;/code&gt; can't be pip installed, so getting it set up can be tricky. I can't count how many times I've joined a project, and my initial experience looks like this&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Try to install additional dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run into an error preventing the install&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Message Teams Chat, “Hey, has anyone run into this error when installing X?”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Oh yea, the link they give in the documentation is to an old version of X, this Stack Overflow post has the correct link"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;*Continues trying to install and runs into problem Y*&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ask in the chat again&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Oh it’s because your using version ZZZ for this, you have to downgrade it because Y is expecting a version QQQ instead."&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Eventually you get it all working, and go on your merry way. 3 months later, it is summer and you have new interns. One of them has been assigned to this project to help. All of a sudden you see a Teams message in chat from the new intern.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;“Hey has anyone run into this error when installing X?”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You: *Thinks very hard*. "Oh I remember this error! Hold on I have a link to a Stack Overflow post that has the fix"&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repeat steps 4-7 as your intern struggles with the same issues you had 3 months ago. &lt;/p&gt;

&lt;p&gt;If only there was some way you could construct your software applications, that would allow it to behave in a consistent and efficient way, regardless of the computer environment it's  running on. Wait! What's that I hear you say? There is? Why yes! Docker of course! &lt;/p&gt;

&lt;h1&gt;
  
  
  Docker In Practice
&lt;/h1&gt;

&lt;p&gt;Let’s use our previous example for a simple Python app that performs ocr, and prints out the text to the screen.&lt;/p&gt;

&lt;p&gt;The following code takes a trimmed pdf from the &lt;a href="https://tile.loc.gov/storage-services/public/gdcmassbookdig/autobiographyofb06fran/autobiographyofb06fran.pdf" rel="noopener noreferrer"&gt;Autobiography of Benjamin Franklin&lt;/a&gt; pages 7-17, and prints it out to the console.&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;pytesseract&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pdf2image&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;convert_from_path&lt;/span&gt;

&lt;span class="n"&gt;pdf_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trimmed_autobiography.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Convert PDF pages to images
&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;convert_from_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# DPI set to 300
&lt;/span&gt;
&lt;span class="c1"&gt;# OCR each page and extract text
&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;pytesseract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&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;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now let’s look at the Dockerfile we need to build this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim-bookworm&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Install Tesseract OCR, poppler-utils, and their dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; tesseract-ocr poppler-utils &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;apt-get clean

&lt;span class="c"&gt;# Install python packages&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; pytesseract pdf2image

&lt;span class="c"&gt;# Copy the main.py and PDF file into the Docker image&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; main.py trimmed_autobiography.pdf /app/&lt;/span&gt;

&lt;span class="c"&gt;# Command to run the Python script&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python3", "main.py"]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's a break down each line of this Dockerfile:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FROM python:3.12-slim-bookworm&lt;/code&gt;: This line specifies the base Image to use for building the Docker Image. In this case, we are using an Image named &lt;code&gt;python&lt;/code&gt; with the tag &lt;code&gt;3.12-slim-bookworm&lt;/code&gt;, which means it's based on Python 3.12 and the Debian 'slim' variant. Slim is a smaller version of Debian without extra packages. We use the Python version of Debian instead of the normal Debian Image due to the fact that regular Debian disallows global pip installs (this is normally a good thing).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt;: This line sets the working directory inside the Docker container to &lt;code&gt;/app&lt;/code&gt;. It's common practice to put the code for a project in &lt;code&gt;/app&lt;/code&gt; but your working directory can be anywhere you want. The folder will be created if it isn’t there already. Subsequent commands will be executed from inside this directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp;&lt;/code&gt;: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;RUN&lt;/code&gt; Is a Docker instruction that executes commands in the container during the build process. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apt-get update&lt;/code&gt; Uses the Debian Advanced Package Manager (Apt) to update the package lists for packages that are available for installation. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; Allows for multiple commands to be run in a single RUN instruction and the \ allows the instruction to continue onto the next line. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apt-get install -y tesseract-ocr poppler-utils &amp;amp;&amp;amp;&lt;/code&gt;: This line installs the packages &lt;code&gt;tesseract-ocr&lt;/code&gt; and &lt;code&gt;poppler-utils&lt;/code&gt; along with their dependencies using the apt-get install command. The &lt;code&gt;-y&lt;/code&gt; flag automatically confirms any prompts during installation. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apt-get clean&lt;/code&gt;: This command removes any unnecessary files and packages that were downloaded during the installation process. It helps to keep the Docker image size smaller.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;RUN pip3 install --no-cache-dir pytesseract pdf2image&lt;/code&gt;: This command installs Python packages &lt;code&gt;pytesseract&lt;/code&gt; and &lt;code&gt;pdf2image&lt;/code&gt; using pip. The &lt;code&gt;--no-cache-dir&lt;/code&gt; option disables caching of downloaded packages and metadata.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;COPY main.py trimmed_autobiography.pdf /app/&lt;/code&gt;: This line copies files &lt;code&gt;main.py&lt;/code&gt; and &lt;code&gt;trimmed_autobiography.pdf&lt;/code&gt; from the host machine into the &lt;code&gt;/app&lt;/code&gt; directory within the Docker container.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;CMD ["python3", "main.py"]&lt;/code&gt;: This is the default command to run when the container starts. It specifies to run the &lt;code&gt;main.py&lt;/code&gt; Python script using the python3 interpreter.&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;A Dockerfile is kind of like as a script you would run if you wanted to automate setting up a new laptop. It would specify all the tools and their dependencies you would need and then go and fetch and install them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Docker Image
&lt;/h2&gt;

&lt;p&gt;Now that we have a Dockerfile we can use it to make a Docker Image. If you open your terminal and run &lt;code&gt;docker build -t book-slim .&lt;/code&gt; with this Dockerfile in the current directory, Docker will build a Docker Image based on the instructions provided in the Dockerfile. &lt;br&gt;
Once the image is created, you can run the Docker Image with the command &lt;code&gt;docker run --name book-slim-container book-slim&lt;/code&gt;.  This executes your docker Image named &lt;code&gt;book-slim&lt;/code&gt; and gives the running container the name &lt;code&gt;book-slim-container&lt;/code&gt;. This is helpful because all running Images need a name. If you don’t provide one than docker will make up a name.&lt;/p&gt;

&lt;p&gt;Looking at my Docker Desktop app, I can see that when I executed my Docker Image the first couple of times without specifying a name, Docker gave it the name “trusting_nightingale”, and “nostalgic_shaw”. But when I specified a &lt;code&gt;--name&lt;/code&gt;, that was the name it gave my container instead.&lt;/p&gt;

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

&lt;p&gt;Getting back to our running program, after waiting patiently you should start seeing text printed out to the screen&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My father had also, by the same wife, four&lt;br&gt;
children born in America, and ten others by&lt;br&gt;
a second wife, making in all seventeen. I&lt;br&gt;
remember to have seen thirteen seated to-&lt;br&gt;
gether at his table, who all arrived at years&lt;br&gt;
of maturity, and were married. I wus the&lt;br&gt;
last of the sons, and the youngest chiid, ex-&lt;br&gt;
cepting two daughters. I was born at Bos-&lt;br&gt;
ton, in New England. My mother, the sec-&lt;br&gt;
ond wife, was Abiah Folger, daughter of&lt;br&gt;
Peter Folger, one of the first colonists of&lt;br&gt;
New England, of whom Cotton Mather makes .&lt;br&gt;
honorable mention, in his Ecclesiastical His-&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, we built our Docker Image which specified all the dependencies we need to run the program, then we ran our Image, and it executed the &lt;code&gt;main.py&lt;/code&gt; to print the pdf's text to the terminal like we asked it to. Run the command in the terminal again, but be warned it will fail. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run --name book-slim-container book-slim&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the error message you will get&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

docker: Error response from daemon: Conflict. The container name "/book-slim-container" is already in use by container "5bf83a1f62e4e6191fd502b889282334a1e666b42f473ed43e3d61fc87ac013c". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The reason for this is that Docker requires each container to have a unique name, and we already created one named &lt;code&gt;book-slim-container&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To resolve this, we have a few options...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Remove the existing container&lt;/strong&gt;: You can remove the existing container with the conflicting name using the &lt;code&gt;docker rm&lt;/code&gt; command.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

docker rm book-slim-container
or
docker rm 5bf83a1f62e4e6191fd502b889282334a1e666b42f473ed43e3d61fc87ac013c


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rename the existing container&lt;/strong&gt;: If you want to keep the existing container but use a different name for the new one, you can rename the existing container using the &lt;code&gt;docker rename&lt;/code&gt; command&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker rename book-slim-container new-name&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Restart and re-execute the container&lt;/strong&gt;: An existing container can be restarted, and then re-executed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker restart book-slim-container &amp;amp;&amp;amp; docker exec book-slim-container python3 main.py&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Avoid the issue altogether&lt;/strong&gt;: Because an already created Docker Image is easy to execute as a container, it is common to pass the parameters &lt;code&gt;--rm&lt;/code&gt; to delete the container after it is run, so subsequent runs can just recreate themselves using the same container name and Image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker run --rm --name book-slim-contaner book-slim&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring containers
&lt;/h2&gt;

&lt;p&gt;Let’s peel back the veil a bit on the container itself. Run the following command in the terminal.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run --name book-slim-container -it book-slim /bin/bash&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here’s what these new commands do&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-i&lt;/code&gt;: Stands for "interactive mode". This means that the container's standard input will remain open even if not attached&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-t&lt;/code&gt;: Stands for "tty" or "pseudo-terminal". It allocates a pseudo-terminal for the container&lt;/li&gt;
&lt;li&gt;Together, &lt;code&gt;-it&lt;/code&gt; ensures that the container session is interactive, allowing you to interact with the shell running inside the container
*&lt;code&gt;/bin/bash&lt;/code&gt;: Overrides the default command specified in the Dockerfile (python3 main.py) and starts a bash shell (/bin/bash) inside the container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the interactive command ran successfully, you should be inside the container in the &lt;code&gt;WORKDIR /app&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;If you type &lt;code&gt;ls&lt;/code&gt; you can see the two files that were copied into the container when the Docker Image was built. You can do &lt;code&gt;python --version&lt;/code&gt; and see that the python version is 3.12 and run the &lt;code&gt;main.py&lt;/code&gt; file manually. It all works like you would expect. When you are done exploring the container you can type &lt;code&gt;exit&lt;/code&gt; in the terminal.&lt;/p&gt;

&lt;p&gt;So the advantage of this approach is that you do all the hard work of figuring out all the dependencies for a project, and then encode that into a Dockerfile. Then your coworkers, friends, or collaborators just need to have Docker installed, and then they can run two simple commands to get up and running with your project&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

docker build -t  book-slim .
docker run --rm --name book-slim-contaner book-slim


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Mounting volumes
&lt;/h2&gt;

&lt;p&gt;Let’s make our python program more useful. Instead of printing out the text from the pdf, let’s save it to a file. Here is the new &lt;code&gt;main.py&lt;/code&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;pytesseract&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pdf2image&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;convert_from_path&lt;/span&gt;

&lt;span class="n"&gt;pdf_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trimmed_autobiography.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Convert PDF pages to images
&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;convert_from_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# DPI set to 300
&lt;/span&gt;
&lt;span class="c1"&gt;# OCR each page and extract text
&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;pytesseract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extracted_text.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Text extracted and written to:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If we were to run the Docker Image now with&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run --rm --name book-slim-container book-slim&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;extracted_text.txt&lt;/code&gt; would not be written in the same directory you ran the Docker Image. It would write inside the container, and then get cleaned up once the container finishes running. To make the written file accessible outside of the container, you want to mount a directory using the &lt;code&gt;-v&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Mounting a host directory into a Docker container allows you to share files and directories between the host machine (where Docker is running) and the container. When you mount a directory, you're essentially creating a link between a directory on your host system and a directory inside the container. This has 3 advantages&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Access to Host Files&lt;/strong&gt;: Any files or directories in the mounted directory on the host machine are accessible from within the container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Persistence of Data&lt;/strong&gt;: Changes made to files or directories in the mounted directory from within the container persist on the host machine, and vice versa. This means that if a file is created, modified, or deleted in the mounted directory from either the host or the container, the change will be reflected in both places.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sharing Resources&lt;/strong&gt;: Mounting a directory can be useful for sharing resources such as code, configuration files, or data between the host and the container. This is particularly handy during development or when you need to provide input data or retrieve output data from a container.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the full command to replicate this behavior.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run --rm --name book-slim-container -v .:/app book-slim&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To make sure the file is written locally, I pass &lt;code&gt;.:/app&lt;/code&gt; to the &lt;code&gt;-v&lt;/code&gt; command. This mounts the current directory ‘.’ on the host machine to the &lt;code&gt;/app&lt;/code&gt; directory inside the container.&lt;/p&gt;

&lt;p&gt;After a few moments, &lt;code&gt;extracted_text.txt&lt;/code&gt; appears, confirming that I successfully wrote the file to disk&lt;/p&gt;

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

&lt;p&gt;And that's the basics of Docker. There are still many other aspects of Docker worth getting into (Docker-Compose, managing multiple docker containers, exposing ports, etc) but this should at least get you started. In the mean time, I hope that this article made Docker more approachable, and I hope you use it in one of your next projects!&lt;/p&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/" rel="noopener noreferrer"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>docker</category>
      <category>python</category>
    </item>
    <item>
      <title>The DOIT philosophy: How I'm avoiding Decision Fatigue and the Paralysis of Choice</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Thu, 21 Mar 2024 12:48:45 +0000</pubDate>
      <link>https://dev.to/deusinmachina/the-doit-philosophy-how-im-avoiding-decision-fatigue-and-the-paralysis-of-choice-27bg</link>
      <guid>https://dev.to/deusinmachina/the-doit-philosophy-how-im-avoiding-decision-fatigue-and-the-paralysis-of-choice-27bg</guid>
      <description>&lt;p&gt;My mantra for this year is DOIT and it stands for&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;D&lt;/strong&gt;O&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O&lt;/strong&gt;vercome&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I&lt;/strong&gt;terate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;T&lt;/strong&gt;riumph&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have a lot of projects that are in various states of completion, and I want to get them over the finish line. I just need to DOIT. In service of this, another goal of mine in 2024 is simplicity. By focusing on simplicity I will be able to more effectively achieve my project goals. Einstein's famous quote is applicable here&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It can scarcely be denied that the supreme goal of all theory is to make the irreducible basic elements as simple and as few as possible without having to surrender the adequate representation of a single datum of experience&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Amusingly, the more familiar version of this quote is actually a simplified version of the former. It illustrates the point well...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everything should be made as simple as possible, but no simpler&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key is the 2nd part of the quote "but no simpler". Complexity is the bane of Programmers, and I've been making my life more complicated than it has to be recently. Sure, there are things that are complex just by their very nature, and just like how I wouldn't fear 1 duck, but 100,000 would give me pause, a 100,000 line code base would still be challenging to work with no matter what the language. But at least languages that value simplicity leave more space in your brain for the actual code part, so you don't end up looking like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8whk1pfn5l9wjow9gnl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8whk1pfn5l9wjow9gnl.jpg" alt="person trying to fit large code base in their brain but there isn't enough space" width="500" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or as Andrew Kelly puts it with Zig&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Focus on debugging your application rather than debugging your programming language knowledge.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ultimately what we are trying to do as Programmers is create things, and complexity gets in the way of that. But the complexity which has inhibited my ability to complete projects doens't just stop at what programming languages I am using, there are other things that cause complexity, and they result in two things. Decision fatigue and the Paralysis of Choice. Let's get a baseline for how these are defined&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decision Fatigue:&lt;/strong&gt; The deteriorating quality of decisions made by an individual after a long session of decision making. Essentially, the more decisions you make, the more your ability to make further decisions diminishes. This is because making decisions is cognitively taxing, and over time, the mental resources needed to weigh choices, foresee outcomes, and make judgments become depleted. &lt;em&gt;As a result, an individual might resort to simpler decision-making strategies, exhibit reduced self control, or even avoid making decisions altogether as they become fatigued.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Paralysis of Choice:&lt;/strong&gt; When an individual is faced with too many options and finds it difficult to make a decision. Instead of making a choice, the person becomes overwhelmed by the options available and may feel anxious or unable to choose at all. The paralysis of choice suggests that having too many options can lead to less satisfaction with the eventual choice made, due to the stress of the selection process and the potential for regret over the alternatives not chosen.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it affects people
&lt;/h2&gt;

&lt;p&gt;The important thing to note about the two definitions above is that it doesn't say anything about a specific scenario where this happens. It is simply the act of decision making, and the number of choices that cause the problems. This is why &lt;a href="https://www.cnbc.com/2019/06/07/why-successful-people-wear-the-same-thing-every-day.html"&gt;successful people employ the trick&lt;/a&gt; of wearing the same close to reduce the amount of decisions they make. But while this is definitely not a live like a "billionaire" grindset sort of article, the principles are sound. CEOs simplify their lives so they can make big decisions that steer the direction of companies and billions of dollars in capital. But we can do the same thing to be more successful in achieving more goals. &lt;/p&gt;

&lt;h2&gt;
  
  
  How it affects me
&lt;/h2&gt;

&lt;p&gt;To this end I've tried to simply many aspects of my life. One way I've done this is cutting down to one large monitor. This might seem controversial as the productivity gain from two is almost double a single monitor. But a second monitor also invites temptation. It's easy to put things on that 2nd screen that are just for entertainment and don't serve the current task at hand. Furthermore, I find the little snags that come with a 2nd monitor interrupt my flow when I'm working on things. For example&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Windows opening on the wrong screen &lt;/li&gt;
&lt;li&gt;Windows opening between two screens&lt;/li&gt;
&lt;li&gt;Resolution issues when both monitors are not the same size&lt;/li&gt;
&lt;li&gt;Deciding which monitor a window should be on&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The point is not that these things can't be fixed, it's that they require three things of mine that are in limited supply. My concentration, my decision making energy, and my will power to not watch YouTube videos. I would rather alt tab to another window when I really need it, or split my window in two so I can read the documentation. Plus with one monitor I don't have to worry about one screen being in a suboptimal position. Everything is always comfortably in my vision.&lt;/p&gt;

&lt;p&gt;Another way I am simplifying my life is to stick to one operating system. I would switch distributions multiple times a year, as the sheen of the new one faded. This required me to spend a better part of the day just setting up everything again, and then another month running into things I had to set up because I used them so infrequently. This year I'm forcing myself to stick with Pop!_OS as my main desktop's operating system. Pop!_OS is good, so this isn't the hardest decision, but speaking it into existence as opposed to privately muttering it to my self provides some accountability.&lt;/p&gt;

&lt;p&gt;I'm also cutting down on the number of programming languages I will start new projects in. I've been hopping programming languages like I hop distributions, and while I've appreciated the breadth of experience this has given me, I find that it has caused me to have very shallow experience in a lot of languages that aren't Python. Furthermore, a lot of my projects start with me just digging into what programming language I'm going to use, what libraries are available for the task, and how to make my code more idiomatic. I find myself trying to Goldilocks myself into the right programming for the project, but it never works. This paralysis of choice has a subtle but deadly side effect that I have been feeling more frequently too&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;leading to less satisfaction with the eventual choice made, due to the stress of the selection process and the potential for regret over the alternatives not chosen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Less satisfaction and regret, two things I don't need more of in my life. Along these same lines I will reduce the number of categories these projects fall under. From GUI to Games, Programming Language Theory to Machine Learning, and Art to Level Design, I've doing a lot of things that cover a lot of different topics. They are all interesting, and I wish I could spend all every waking moment hoping between them, but I will never reach the level of proficiency I want to be at if I spread myself so thin.&lt;/p&gt;

&lt;p&gt;Finally as programmers there are tons of decisions we have to make related to...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Programming languages&lt;/li&gt;
&lt;li&gt;Frameworks&lt;/li&gt;
&lt;li&gt;Windows vs Mac vs Linux&lt;/li&gt;
&lt;li&gt;Mechanical Keyboard Switches&lt;/li&gt;
&lt;li&gt;frameworks&lt;/li&gt;
&lt;li&gt;Wall Paper Color&lt;/li&gt;
&lt;li&gt;Text Editor Font&lt;/li&gt;
&lt;li&gt;Text Editor&lt;/li&gt;
&lt;li&gt;ECS, Functional, OOP&lt;/li&gt;
&lt;li&gt;Web, Mobile Desktop&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before we've even written a single line of code. It's no wonder so many of us want to start a farm instead. But I'm saying let's not throw the baby out with the bath water. Maybe I can pare things down a bit and focus on actually putting code to text editor. And if I don't pick the perfect stack for my project, who cares, just deal with it. My programming ancestors did more with less. Now I'm not saying to &lt;a href="https://www.levels.fyi/blog/scaling-to-millions-with-google-sheets.html"&gt;scale your product to millions of users using just Google Sheets&lt;/a&gt;, but it's hard to go wrong with a mainstream language today.&lt;/p&gt;

&lt;p&gt;Of course, I will still learn new things for my job, and I will still write about the interesting things I do here. But I will cut back in places that I can. As it currently stands I have over a years worth of drafts saved up, so even if I just draw inspiration from my drafts it will cover me well into 2025. But, as the year is not even close to over, I suspect I'll come across more little nuggets that will spark ideas for new articles. In the mean time, I hope to get some projects completed as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>A World Without C</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Thu, 07 Mar 2024 13:02:56 +0000</pubDate>
      <link>https://dev.to/deusinmachina/a-world-without-c-3jf9</link>
      <guid>https://dev.to/deusinmachina/a-world-without-c-3jf9</guid>
      <description>&lt;p&gt;&lt;a href="https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf"&gt;The Whitehouse released a report&lt;/a&gt; this week encouraging the use of memory safe languages, over non memory safe languages, specifically calling out C/C++. This has obviously caused a stir in the programming community, especially considering most people's low opinion of the government’s ability to produce quality software. But if you’ve used a computer in the last year you’ve probably been subjected to poor quality software made by the brightest minds in Silicon Valley, so it's a moot point  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffy8lyhxph63eofdrxyqv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffy8lyhxph63eofdrxyqv.jpg" alt="Epic Handshake but with the governement and silicon valley" width="697" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Missing Points
&lt;/h2&gt;

&lt;p&gt;What I find surprising in all of this discourse is that people have missed the point, intentionally or not. Memory unsafe languages have footguns that lead to unsafe software, and that leads to CVEs that cause harm to real people. The context for the report is not your hobby project, nor your single player 2D platformer. It’s about software that power governments and institutions, places that store large amounts of people’s data etc. It’s about companies that provide live services to millions of people, and store their credit card numbers, phone numbers, addresses, names, and dates of birth. This also not about it becoming illegal to program in memory unsafe languages. To sum it up&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Programmers writing lines of code do not do so without consequence; the way they do their work is of critical importance to the national interest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Enduring Legacy of C
&lt;/h2&gt;

&lt;p&gt;A lot of the discourse revolves around C, with the main point being that you will never get rid of it. That the world runs on C, your operating system runs on C, your programming language runs on C etc, etc. I know how important C is, I've written multiple articles that feature C prominently, and I'll probably write some more&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.deusinmachina.net/p/history-of-unix"&gt;Tracing the Lines: From the Telephone to Unix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.deusinmachina.net/p/c-strings-and-my-slow-descent-to"&gt;C Strings and my slow descent to madness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.deusinmachina.net/p/understanding-the-compilation-process"&gt;Understanding the Compilation Process in C: A Step by Step Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.deusinmachina.net/p/sdl-tutorial-part-1-opening-a-window"&gt;SDL Tutorial Part 1: Opening A Window&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a lot of reasons for C's dominance in the modern era, but the one that sticks out to me is that it is the lowest common denominator for just about everything. If you write something in C, it is straightforward in most languages to bind to it through an FFI. That means if I for instance, come across a cool C library that does exactly what I need, I can just bind the functions in my Python code without knowing all the nitty gritty details of how it's implemented. I can do it again in Go, and Java and C# and on and on. Just look at the list of programming languages that have Raylib bindings to see how powerful of a concept this can be&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pwocxjl5mkqd15x23nx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pwocxjl5mkqd15x23nx.png" alt="Table showing all the bindings for Raylib" width="800" height="827"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  C's Simplicity and Its Challenges
&lt;/h2&gt;

&lt;p&gt;But Cs greatest strength is also its greatest weakness. It's simple. My 2nd Edition of K&amp;amp;R is just shy of 300 pages, but a good chunk of that is a reference manual, and a chapter on lexical conventions which can be skipped on a first read through. You could skim through the book in a day. But while the syntax may be simple, there are a lot of concepts in C that are tricky to get right, especially in large programs&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pointer Arithmetic&lt;/li&gt;
&lt;li&gt;Memory Management&lt;/li&gt;
&lt;li&gt;Headers/Preprocessor&lt;/li&gt;
&lt;li&gt;Macros&lt;/li&gt;
&lt;li&gt;Undefined Behavior&lt;/li&gt;
&lt;li&gt;Strings and Cross Platform string behavior/support&lt;/li&gt;
&lt;li&gt;Actually building large projects&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And you don't have to take my word, here is C++ being brought up again as an alternative to C in the &lt;a href="https://lore.kernel.org/lkml/3465e0c6-f5b2-4c42-95eb-29361481f805@zytor.com/"&gt;Linux Kernel&lt;/a&gt; just this year (2024), by someone who has programmed more C than I ever will in my lifetime. And here is a page that &lt;a href="https://lwn.net/Articles/542457/"&gt;details GCC's transition to C++&lt;/a&gt; (the irony is not lost on me). If these people are the best C programmers in the world, what chance do I have? Even John Carmack talks about being surprised in the Lex Fridman podcast about how many mistakes he found when he attacked his code base with sanitizers and fuzzing. &lt;/p&gt;

&lt;p&gt;You might ask, well can't we just make C a better language? And the answer is yes, but that takes time. I'm really looking forward to many of the changes that are in C23, but it will be many years before that will be widely available across MSVC, Clang, and GCC. And getting any feature into C is an exercise in frustration. You only have to read JeanHeyd Meneide's article titled &lt;a href="https://thephd.dev/finally-embed-in-c23"&gt;Finally, Embed in C23&lt;/a&gt; to understand how thankless of a task this is. I'll give you one excerpt, but I've seen this same sentiment time and time again when it comes to improving the language&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s deeply depressing and ultimately a great source of burnout being at the grindstone for 4 years for things people were casually discussing about in September of 1995 (and earlier). It’s almost as depressing as putting typeof in the C Standard and then realizing this was something they’d been discussing doing since after C89 (1989). Am I destined to just keep closing the loop on old, unrealized dreams because a bunch of people were too tired/scared/busy/combative to standardize what has literally been decades of existing practice?&lt;br&gt;
 It was hard to realize how tired I was of this kind of grind until the day the feature was put into the C Standard, this past Tuesday. I quite literally could not even muster a “yes!” after the vote finished. I just felt empty and numb, because quite literally dragging an entire community of implementers through several hurdles, to finally get them to acknowledge the existence of a problem and its solution, is just… soul-crushing. It is a level of effort that I recommend to nobody in any sphere of life, for any task. At least when you are on the ground and organizing and helping people, you’re providing some kind of material value. Water. Food. Improving something. Here? I’m talking about things that are quite literally older than I am. Just trying to bring ideas from the last 3 decades - things you would think were Table Stakes for foundational languages like C and C++ languages - would not be seen as a radical new paradigm or shift in the language. Nevertheless, I spent (burned?) that energy, and finally. It's in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That doesn't sound like a fun process to me...&lt;/p&gt;

&lt;p&gt;Now if you're still here I want to make it clear that there are qualities of C that I admire. It's an important language in the annals of programming history, and it is well worth learning. I love C's Spartan nature when I'm practicing Algorithms and Data Structures, and I appreciate that it produces software that is small and fast. Today's modern programming languages have done a shit job at filling in the C's shoes, which is why it's still around so prominently. I think of all the programming languages out there, Zig is the one I'm most hopeful for replacing C in what C does best. And it does so while being safer, easier to cross compile and build, and without adding a ton of complexity to the syntax like languages like Rust, D, and C++ do. Now to my main point...&lt;/p&gt;

&lt;h2&gt;
  
  
  Envisioning a Post C World
&lt;/h2&gt;

&lt;p&gt;It is worth noting that C didn't appear on the scene until 1972. That means that 60% of the population in the United States has been around longer, and there are plenty of programmers that remember a world where C didn't exist. C was also absent in the early 8-Bit era compared to programming languages like Basic, Pascal, and Assembly due to its difficulty to compile. So really it's only like 45 years that C has been a major player in the programming space. But people keep repeating the same mantra over and over again "C will never die", which feels like a shocking amount of small mindedness coming from the programming community. I thought we were supposed to be innovative thinkers, problem solvers, and engineers. Must we forever be shackled to a programming language we created 50 years ago, in field that is only 75 years old? Is it really not possible to envision a world that isn’t powered by C or C++ even if it takes another 50-100 years? &lt;/p&gt;

&lt;p&gt;Two Years ago no one was talking about Large Language Models. We were still 30 years away from anything remotely resembling a useful AI assistant. Now, one year later my &lt;em&gt;Church&lt;/em&gt; is using AI Generated images from ChatGPT in their service, and Nvidia has doubled its stock priced in a year. 8 Years ago Visual Studio Code was released, and now it is the most popular text editor by far. The programming space can move quickly if the value is there, and I believe that moving away from C is one of those things. If our best years of programming are still to come (and I hope they are), and we expect more code to be written in the next few years than at any other point in history, then the percentage of C code should dwindle every year. If the financial incentives are there, and if governments will start biasing favor towards more memory safe languages, then there will be a strong incentive for certain companies to comply.&lt;/p&gt;

&lt;p&gt;Replacing C does not mean erasing its legacy. I will continue to write about C, and tell its part in the ever evolving history of programming, and I hope you will continue to enjoy the story as it is written.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call To Action
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>c</category>
    </item>
    <item>
      <title>Experimenting with GUIs on the Pi Zero</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Sat, 02 Mar 2024 23:18:56 +0000</pubDate>
      <link>https://dev.to/deusinmachina/experimenting-with-guis-on-the-pi-zero-2428</link>
      <guid>https://dev.to/deusinmachina/experimenting-with-guis-on-the-pi-zero-2428</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fat72zpifio5naqkjfbrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fat72zpifio5naqkjfbrf.png" alt="tkinter gui for querying openai api" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently brought an old Raspberry Pi Zero back to life. With the oldest files dating back to the summer of 2020, it was safe to say that it was time for a fresh install. Thankfully there is still a version of Raspberry Pi OS that supports 32 bit Raspberry Pi's like the Zero W &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrygg5n111bhj3zb7g7o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrygg5n111bhj3zb7g7o.png" alt="Raspberry Pi OS download screen" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It comes with Bookworm which is a recent Debian release, which means we get nice goodies like Python 3.11, version 6+ of the Linux kernel (up from 4.19 in the old install), and newer versions of lots of other software. Not that I'll be using the RPI Zero much like a Desktop. A 32-bit single core CPU clocked at 1 Ghz, with 512Mb of RAM, is basically abandonware at this point as a Desktop platform. Even the default installer from the Raspberry Pi foundation installs software you can't use. It asks whether you want to install Chromium and or Firefox, but both programs say this when you try to use them&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Chromium/Firefox is not supported on the Raspberry PI Zero W&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whether it's actually realistic to use the Raspberry Pi Zero as a Desktop is a boring question. Who cares! It's fun. But anyway, I'm more interested in using the Zero W to test the baseline performance of some apps that I'm writing anyways, so this isn't a problem. Let's start by looking at a couple of programs on the Pi Zero and see how they perform out of the box. The answer... Pretty slow, but not as bad as I was expecting. Opening up basic software like the terminal, and the file browser take anywhere from 3-6 seconds. That's definitely slow, but even on my beefy desktop with an SSD, most of the apps I use take at least 1-3 seconds to start up. That's not even an order of magnitude faster on a machine that is much more powerful. But complaining about software performance in 2024 is so passé so I'll just say it sucks. It did pique my interest in performing some highly unscientific testing though which is what you will get below.&lt;/p&gt;

&lt;p&gt;Being nerdsniped by timing random apps opening, I decided to write some basic GUI apps that did nothing more than open an &lt;code&gt;800x600&lt;/code&gt; window, and time them on my phone. Starting off with GTK, I modified the basic &lt;a href="https://docs.gtk.org/gtk4/getting_started.html"&gt;GTK4 tutorial example&lt;/a&gt;&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;gtk/gtk.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;activate&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GtkApplication&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;gpointer&lt;/span&gt;        &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;GtkWidget&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gtk_application_window_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;gtk_window_set_title&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GTK_WINDOW&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"Window"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;gtk_window_set_default_size&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GTK_WINDOW&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;gtk_window_present&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GTK_WINDOW&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&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;int&lt;/span&gt;    &lt;span class="n"&gt;argc&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;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;GtkApplication&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;app&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;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gtk_application_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.gtk.example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;G_APPLICATION_DEFAULT_FLAGS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;g_signal_connect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"activate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;G_CALLBACK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activate&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="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;g_application_run&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G_APPLICATION&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;g_object_unref&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&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;status&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;Compiling the tutorial with the -O2 optimization set, I was astonished to see the app take between 12-14 seconds to open a blank window. Now GTK4 does a lot for us out of the box, and that comes with an upfront cost. But for a blank window that is pretty bad. I looked around for some examples of deploying apps on resource constrained systems with GTK, and even &lt;a href="https://discourse.gnome.org/t/optimizing-startup-time-of-gtk4-0-apps-on-rpi-zero/19637"&gt;asked in the GNOME forums&lt;/a&gt; but couldn't find any solutions. If you know of any please let me know.&lt;/p&gt;

&lt;p&gt;With that shocking result, I decided to get a baseline for how fast a window &lt;em&gt;could&lt;/em&gt; open up. I did this by making as simple X application that opens a window, and then timing the result...&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;X11/Xlib.h&amp;gt;&lt;/span&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="c1"&gt; // For exit function&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="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Display&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Window&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;XEvent&lt;/span&gt; &lt;span class="n"&gt;event&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;screen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Open connection to the X server&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XOpenDisplay&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cannot open display&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="n"&gt;exit&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;screen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DefaultScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


    &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XCreateSimpleWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RootWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;screen&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="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&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;BlackPixel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;WhitePixel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;


    &lt;span class="n"&gt;XSelectInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExposureMask&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;KeyPressMask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


    &lt;span class="n"&gt;XMapWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&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;XNextEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Break out of the loop if the user presses any key&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;KeyPress&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="p"&gt;}&lt;/span&gt;


    &lt;span class="n"&gt;XCloseDisplay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display&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;Except, I almost didn't have a chance to time the result, as the window opened up in ~0.5 seconds. I'll be the first to tell you this is not an Apples to Apples comparison, and writing a GUI using just X11 would be an exercise in suffering. (I mean but that's basically what Casey Muratori did in his &lt;a href="https://www.youtube.com/watch?v=T4CjOB0y9nI&amp;amp;list=PLnuhp3Xd9PYTt6svyQPyRO_AAuMWGxPzU&amp;amp;index=6"&gt;Handmade Hero Series&lt;/a&gt; for Windows). But if all apps opened at that speed, my RPI Zero W wouldn't feel slow at all. Armed with this new knowledge, I decided to look at a couple of other ways of opening a window.&lt;/p&gt;

&lt;p&gt;Since I've been on an SDL2 kick recently, it only made sense to do the same test with that library. You make recognize this code as essentially the example I wrote in &lt;a href="https://open.substack.com/pub/deusinmachina/p/sdl-tutorial-part-1-opening-a-window?r=1nv6s0&amp;amp;utm_campaign=post&amp;amp;utm_medium=web&amp;amp;showWelcomeOnShare=true"&gt;SDL Tutorial Part 1: Opening A Window&lt;/a&gt; from a couple weeks ago&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;SDL2/SDL.h&amp;gt;&lt;/span&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;
&lt;/span&gt;
&lt;span class="cp"&gt;#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SDL_Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SDL_INIT_VIDEO&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;0&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;"Couldn't initialize SDL: %s&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="n"&gt;SDL_GetError&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;EXIT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;SDL_Window&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SDL_CreateWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Example: 0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SDL_WINDOWPOS_UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;SDL_WINDOWPOS_UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_HEIGHT&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;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;window&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;"Failed to open %d x %d window: %s&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="n"&gt;SCREEN_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SDL_GetError&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;EXIT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;SDL_Renderer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SDL_CreateRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_RenderClear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_Delay&lt;/span&gt;&lt;span class="p"&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;SDL_DestroyWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_Quit&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;EXIT_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our results... A little over 3.1 seconds. While SDL2 is not a retained mode GUI, I could certainly do more with it than I could with just a raw X app. So, so long as people didn't need a screen reader for the program, this might be a viable option. (I'm not even sure you could run any sufficiently complex app, and a screen reader on the RPI Zero, at the same time anyway though).&lt;/p&gt;

&lt;p&gt;I recently made a simple GUI app in Python with Tkinter, and since it's already built into Python I wrote my example in it next to see how it would perform&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;tkinter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tk&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Tk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Simple 800x600 Window&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;800x600&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mainloop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;~2.9 seconds. For an language that has to interpret the code upfront, that is not bad. I think that Tkinter is an underrated gem of the Python world, and I'll be writing more about that soon. But, while the Tk integration with Python is great, I wanted to look at two more implementations. One using the de facto Tcl bindings to Tk, and the other using just raw C and Tk&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env wish&lt;/span&gt;

wm title . &lt;span class="s2"&gt;"Simple Window"&lt;/span&gt;
wm geometry . 800x600

tkwait window .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tcl is an interesting language that warrants its own discussion at a later date, but on my RPI Zero I was able to open up the window in ~2.0 seconds which is a great improvement. Considering we are entering the territory of as fast, or faster than the default apps, I feel like we have reached acceptable speeds. But Python and Tcl are just binding the underlying C Tk library, so let's look at C next.&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;tk.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;int&lt;/span&gt; &lt;span class="n"&gt;argc&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;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Tcl_Interp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;interp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Tk_Window&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Initialize Tcl and the Tk toolkit&lt;/span&gt;
    &lt;span class="n"&gt;Tcl_FindExecutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&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;interp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tcl_CreateInterp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tcl_Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;TCL_ERROR&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tk_Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;TCL_ERROR&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a new top-level Tk window&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tk_MainWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Set the title of the window using Tcl command&lt;/span&gt;
    &lt;span class="n"&gt;Tcl_Eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"wm title . &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Simple Tk C App&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Set the size of the window&lt;/span&gt;
    &lt;span class="n"&gt;Tk_GeometryRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Start the Tk event loop&lt;/span&gt;
    &lt;span class="n"&gt;Tk_MainLoop&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;Honestly maybe a tenth of a second faster than Tcl example but much less ergonomic. I did compile everything with &lt;code&gt;-O2&lt;/code&gt; when I could, but I think that is just a testament to how well Tcl and Tk are integrated.&lt;/p&gt;

&lt;p&gt;Next I looked at the Fast Light Toolkit (FLTK), a cross platform GUI library I used many years ago when I first attempted to learn C++. Fun fact this is also the GUI library used to create the Eureka Doom Level editor, a cross platform tool I have extensive experience with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mn4vwl402k2zk5vc011.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mn4vwl402k2zk5vc011.png" alt="Eureka doom map editor" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's certainly got the right name for this test, so let's see if it can live up to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;FL/Fl.H&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;FL/Fl_Window.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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Create a window with dimensions 800x600&lt;/span&gt;
    &lt;span class="n"&gt;Fl_Window&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Fl_Window&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Set the window label&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My FLTK Window"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Show the window&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Run the FLTK event loop&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Fl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;run&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;Aaand at 1.1 seconds we have a new winner. That was really impressive. I would be curious to see how much of it's speed it could retain with a more complex application. &lt;/p&gt;

&lt;p&gt;To finish this test off, I'll add two late additions. A simple Qt6 app using QT Widgets and C++&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;QApplication&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;QWidget&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;int&lt;/span&gt; &lt;span class="n"&gt;argc&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;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;QApplication&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;QWidget&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setWindowTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Simple Qt6 App on Raspberry Pi Zero"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a QtQuick example with qml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;QtQuick&lt;/span&gt; &lt;span class="mf"&gt;2.15&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;QtQuick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Window&lt;/span&gt; &lt;span class="mf"&gt;2.15&lt;/span&gt;

&lt;span class="nx"&gt;Window&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;
    &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;
    &lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiling these apps made my little Pi Zero chug, but it was worth it. At a little under 2.5 seconds for QT widgets, and 2.75 seconds for the QML example, that's not bad. QT is used a lot in the auto industry for infotainment systems which are not known for their specs, so it's not surprising that we could get something running on our RPI Zero. Qt also comes with all the same goodies that GTK and other fully featured cross platform GUIs would need to build any type of app, so its performance here indicates it would be pretty snappy on any computer more powerful than a Raspberry Pi Zero. It's not my favorite cross platform GUI for a few reasons, but every non electron based desktop GUI developer job I've seen uses it, so that's a strong point in its favor.&lt;/p&gt;

&lt;p&gt;Now, I'll be the first one to tell you that there are a lot more that goes into making a GUI app than how fast it opens. There is the set of widgets that it provides, how cross platform it is, what its memory footprint looks, its ability to provide a native "look and feel" etc. All things we didn't test here. But I hope that I've at least convinced you to give one of these great libraries a try&lt;/p&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>programming</category>
      <category>gui</category>
      <category>raspberrypi</category>
    </item>
    <item>
      <title>SDL Tutorial in C Part 2: Displaying Text</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Fri, 23 Feb 2024 00:20:22 +0000</pubDate>
      <link>https://dev.to/deusinmachina/sdl-tutorial-in-c-part-2-displaying-text-o55</link>
      <guid>https://dev.to/deusinmachina/sdl-tutorial-in-c-part-2-displaying-text-o55</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part 2 of my SDL series using C. If you missed part 1 you can &lt;a href="https://dev.to/deusinmachina/sdl-tutorial-part-1-opening-a-window-133p"&gt;find it here&lt;/a&gt;.📌&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h2&gt;
  
  
  Displaying Text Cheat Sheet
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2_ttf/TTF_Init" rel="noopener noreferrer"&gt;TTF_Init&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wiki.libsdl.org/SDL2_ttf/TTF_OpenFont" rel="noopener noreferrer"&gt;TTF_OpenFont&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2_ttf/TTF_RenderText_Solid" rel="noopener noreferrer"&gt;TTF_RenderText_Solid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_CreateTextureFromSurface" rel="noopener noreferrer"&gt;SDL_CreateTextureFromSurface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_RenderCopy" rel="noopener noreferrer"&gt;SDL_RenderCopy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tutorial
&lt;/h2&gt;

&lt;p&gt;Displaying Text in SDL2 requires a very similar set of operations to how we handled creating a window and renderer in part 1. But before we get to displaying text, we need to include the appropriate header. Since SDL2 is designed to be modular, the libraries that work with text are in their own separate headers/files. To work with text, you will need &lt;code&gt;SDL_ttf.h&lt;/code&gt;. You can either include it and the appropriate files directly in your project, linking them at compile time, or if you are on Linux like I am, use your package manager to install them globally. While we won’t be going over the specifics for how to set up SDL in this tutorial, &lt;a href="https://wiki.libsdl.org/SDL2/Installation" rel="noopener noreferrer"&gt;the SDL Wiki&lt;/a&gt; provides a page on how to properly set up SDL that is pretty thorough. Now, for those of you who just want to see the code, here is the entire source &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

#include &amp;lt;SDL2/SDL.h&amp;gt;
#include &amp;lt;SDL2/SDL_ttf.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
#define MY_FONT "/usr/share/fonts/truetype/freefont/FreeSans.ttf"

int main(){
  if (SDL_Init(SDL_INIT_VIDEO) &amp;lt; 0){
    printf("Couldn't initialize SDL: %s\n", SDL_GetError());
    return EXIT_FAILURE;
  }
    // Initialize SDL_ttf
    if (TTF_Init() &amp;lt; 0) {
        printf("SDL_ttf could not initialize! TTF_Error: %s\n", TTF_GetError());
        SDL_Quit();
        return EXIT_FAILURE;
    }

  SDL_Window *window = SDL_CreateWindow("Drawing Text", SDL_WINDOWPOS_UNDEFINED,
                    SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);

  if (!window){
    printf("Failed to open %d x %d window: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, SDL_GetError());
    return EXIT_FAILURE;
  }

  SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);

  if (!renderer){
    printf("Failed to create renderer: %s\n", SDL_GetError());
    return EXIT_FAILURE;
  }

  SDL_SetRenderDrawColor(renderer, 255,255,255,255);
  SDL_RenderClear(renderer);

  TTF_Font *font = TTF_OpenFont(MY_FONT, 64); // specify the path to your font file and font size

  if (!font){
    printf("Failed to load font: %s\n", TTF_GetError());
    return EXIT_FAILURE;
  }

  // Create surface with rendered text
  SDL_Color textColor = {0, 0, 0, 255}; // black color
  SDL_Surface *textSurface = TTF_RenderText_Solid(font, "Hello World!", textColor);

  if (!textSurface) {
    printf("Failed to create text surface: %s\n", TTF_GetError());
    return EXIT_FAILURE;
  }

  // Create texture from surface
  SDL_Texture *textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);

  if (!textTexture){
    printf("Failed to create text texture: %s\n", SDL_GetError());
    return EXIT_FAILURE;
  }

  // Render text
  SDL_Rect textRect = {50, 50, textSurface-&amp;gt;w, textSurface-&amp;gt;h}; // rectangle where the text is drawn 
  SDL_RenderCopy(renderer, textTexture, NULL, &amp;amp;textRect);

  SDL_RenderPresent(renderer);
  SDL_Delay(2000);
  SDL_DestroyWindow(window);
  SDL_DestroyRenderer(renderer);
  SDL_Quit();

  return EXIT_SUCCESS;
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Starting off we &lt;code&gt;#include &amp;lt;SDL2/SDL_ttf.h&amp;gt;&lt;/code&gt; which gives us access to functions that help us display text. Since the ttf module works with fonts, which are normally, .ttf files, we need a font to properly display the text in our Window. You can either download a font from the internet, or use a .ttf file that you have on your computer. To keep it simple, I’ll just use one of the default ones that comes on my computer. At the top of my program, I've created a define that simply points to a default font&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 #define MY_FONT "/usr/share/fonts/truetype/freefont/FreeSans.ttf"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;On macOS you should be able to find some .ttf files located at &lt;code&gt;/Library/Fonts&lt;/code&gt; and on Windows &lt;code&gt;C:\Windows\Fonts&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Following the same paradigm we used to initialize our SDL video module, we have to initialize our ttf library. The same pattern is used, where we check to see if the return value of the &lt;a href="https://wiki.libsdl.org/SDL2_ttf/TTF_Init" rel="noopener noreferrer"&gt;TTF_Init&lt;/a&gt; function is less than zero, and if it is, we display an error to the user&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    // Initialize SDL_ttf
    if (TTF_Init() &amp;lt; 0) {
        printf("SDL_ttf could not initialize! TTF_Error: %s\n", TTF_GetError());
        SDL_Quit();
        return EXIT_FAILURE;
    }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the ttf library was installed and linked correctly then we can attempt to load a font using &lt;a href="https://wiki.libsdl.org/SDL2_ttf/TTF_OpenFont" rel="noopener noreferrer"&gt;TTF_OpenFont&lt;/a&gt;. Again we want to check that the font was actually loaded and we do that with our if statement&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  TTF_Font *font = TTF_OpenFont(MY_FONT, 64); // specify the path to your font file and font size

  if (!font){
    printf("Failed to load font: %s\n", TTF_GetError());
    return EXIT_FAILURE;
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now that we've loaded our font we need to create a text surface using &lt;a href="https://wiki.libsdl.org/SDL2_ttf/TTF_RenderText_Solid" rel="noopener noreferrer"&gt;TTF_RenderText_Solid&lt;/a&gt; This surface is essentially an image containing the rendered text. Since this is an operation that can fail, we want to make sure that we check this using an if statement like we've done before&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 // Create surface with rendered text
  SDL_Color textColor = {0, 0, 0, 255}; // black color
  SDL_Surface *textSurface = TTF_RenderText_Solid(font, "Hello World!", textColor);

  if (!textSurface) {
    printf("Failed to create text surface: %s\n", TTF_GetError());
    return EXIT_FAILURE;
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step uses &lt;a href="https://wiki.libsdl.org/SDL2/SDL_CreateTextureFromSurface" rel="noopener noreferrer"&gt;SDL_CreateTextureFromSurface&lt;/a&gt; to convert our &lt;code&gt;SDL_Surface&lt;/code&gt; (your rendered text) into an &lt;code&gt;SDL_Texture&lt;/code&gt;. This is necessary because modern SDL2 uses the GPU for rendering, and textures are the GPU-friendly way of handling images. This conversion process uploads the surface data to the GPU memory, enabling efficient rendering. This operation can also fail, so it is important to check that it doesn't before doing anything with the texture&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  // Create texture from surface
  SDL_Texture *textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);

  if (!textTexture){
    printf("Failed to create text texture: %s\n", SDL_GetError());
    return EXIT_FAILURE;
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, we call &lt;a href="https://wiki.libsdl.org/SDL2/SDL_RenderCopy" rel="noopener noreferrer"&gt;SDL_RenderCopy&lt;/a&gt;. This function call tells SDL2 to copy the text texture to the renderer. The &lt;code&gt;SDL_Rect&lt;/code&gt; &lt;code&gt;textRect&lt;/code&gt; that is defined is used to position and size the text on the screen.&lt;/p&gt;

&lt;p&gt;It is important to understand that nothing will be drawn on the screen yet. It's more like preparing what needs to be drawn. The actual drawing happens when you call &lt;a href="https://wiki.libsdl.org/SDL2/SDL_RenderPresent" rel="noopener noreferrer"&gt;SDL_RenderPresent&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  // Render text
  SDL_Rect textRect = {50, 50, textSurface-&amp;gt;w, textSurface-&amp;gt;h}; // rectangle where the text is drawn 
  SDL_RenderCopy(renderer, textTexture, NULL, &amp;amp;textRect);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If all goes well then when you run the code, you should see some text on the screen. With that, you are well on your way to learning the core components of using the SDL2 library. With just the information that you’ve learned from part 1 and part 2, you should be able to make a graphical version of the guess my number game, a common beginner programming task, but with a SDL flavored twist. You could even create a text adventure, if you were so inclined.&lt;/p&gt;

&lt;p&gt;One final note. Between this and the last tutorial, you may be seeing a lot of repetitive code that might be better off abstracted away in functions. That’s good, and means you are getting familiar with the patterns in the library. Opinions about the structure of code should be based off the needs of the code base. While I’m keeping it simple for these tutorials, eventually we should abstract away some common patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Not Draw Directly to the Renderer?
&lt;/h3&gt;

&lt;p&gt;SDL2 uses two main types of objects for drawing: &lt;code&gt;SDL_Surface&lt;/code&gt; and &lt;code&gt;SDL_Texture&lt;/code&gt;. &lt;code&gt;SDL_Surface&lt;/code&gt; is a CPU-based bitmap, useful for manipulating pixel data directly. &lt;code&gt;SDL_Texture&lt;/code&gt;, on the other hand, is GPU-based. Modern SDL2 applications use the GPU for rendering (via &lt;code&gt;SDL_Renderer&lt;/code&gt;), which is faster and more efficient but requires textures, not surfaces.&lt;/p&gt;

&lt;p&gt;The reason you can't directly render the font to the renderer is that &lt;code&gt;SDL2_ttf&lt;/code&gt; is designed to work with surfaces, as historically SDL handled rendering with surfaces before textures and GPU rendering were introduced.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does that mean that SDL2 can render just the surface instead of the texture if I don't want to use the GPU?
&lt;/h3&gt;

&lt;p&gt;Yes, SDL2 can render using just an &lt;code&gt;SDL_Surface&lt;/code&gt; without converting it to an &lt;code&gt;SDL_Texture&lt;/code&gt; if you prefer or need to render without using the GPU. This approach is known as "software rendering" and it's done entirely by the CPU, bypassing the GPU.&lt;/p&gt;

&lt;p&gt;Software rendering with &lt;code&gt;SDL_Surface&lt;/code&gt; was the primary method used in SDL before SDL2 introduced hardware-accelerated rendering with &lt;code&gt;SDL_Texture&lt;/code&gt; and &lt;code&gt;SDL_Renderer&lt;/code&gt;. While software rendering is less efficient and slower than hardware accelerated rendering, it can be useful in certain scenarios, like on systems with limited or no GPU capabilities. Instead of using a renderer like we are using you would instead create a &lt;code&gt;SDL_Surface&lt;/code&gt; with &lt;a href="https://wiki.libsdl.org/SDL2/SDL_GetWindowSurface" rel="noopener noreferrer"&gt;SDL_GetWindowSurface&lt;/a&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;SDL_Surface *windowSurface = SDL_GetWindowSurface(window);&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Call To Action 📣&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/" rel="noopener noreferrer"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>c</category>
      <category>gamedev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>SDL Tutorial Part 1: Opening A Window</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Sat, 17 Feb 2024 16:45:22 +0000</pubDate>
      <link>https://dev.to/deusinmachina/sdl-tutorial-part-1-opening-a-window-133p</link>
      <guid>https://dev.to/deusinmachina/sdl-tutorial-part-1-opening-a-window-133p</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w36k6xjb6uu93o5i4nk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w36k6xjb6uu93o5i4nk.png" alt="SDL Logo" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
I was recently learning SDL2, and I found the lack of tutorials in plain C frustrating. I've decided to be the change I wanted to see in the world, and write my own. This will be a multi-part series, and will serve as a quick reference for how to do common things in SDL2. I've listed the main functions at the top of the tutorial kind of like the Raylib Cheatsheet, if you just need a quick reference.&lt;/p&gt;

&lt;p&gt;Before we dive in, I want to point out an immensely helpful resource that will be useful as you become more experienced.  &lt;a href="https://wiki.libsdl.org/wiki/index"&gt;The SDL2 Wiki&lt;/a&gt; contains an index which has a link to every SDL function wiki page. This will teach you everything you need to know about calling the function and handling its output properly. If a big list of functions is too disjointed, there is also a &lt;a href="https://wiki.libsdl.org/SDL2/APIByCategory"&gt;wikipage&lt;/a&gt; that links to the same resources, but organized into API categories as well. This can be useful as common operations usually require multiple functions that are related.&lt;/p&gt;
&lt;h2&gt;
  
  
  Open a Window Cheat Sheet
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_Init"&gt;SDL_Init&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_CreateRenderer"&gt;SDL_CreateRenderer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_CreateWindow"&gt;SDL_CreateWindow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_SetRenderDrawColor"&gt;SDL_SetRenderDrawColor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_RenderClear"&gt;SDL_RenderClear&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_RenderPresent"&gt;SDL_RenderPresent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_DestroyWindow"&gt;SDL_DestroyWindow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_DestroyRenderer"&gt;SDL_DestroyRenderer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_Quit"&gt;SDL_Quit&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Tutorial
&lt;/h2&gt;

&lt;p&gt;The simplest and fastest way to get a window open in SDL2 is to write the following code.&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;SDL2/SDL.h&amp;gt;&lt;/span&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;
&lt;/span&gt;
&lt;span class="cp"&gt;#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
&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="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;SDL_Window&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SDL_CreateWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Example: 0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SDL_WINDOWPOS_UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SDL_WINDOWPOS_UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_HEIGHT&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;SDL_Renderer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SDL_CreateRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;SDL_RenderClear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;SDL_Delay&lt;/span&gt;&lt;span class="p"&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;SDL_DestroyWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;SDL_Quit&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;EXIT_SUCCESS&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;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2bs17g8gzkyyjtotk7m4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2bs17g8gzkyyjtotk7m4.png" alt="Example white SDL Window" width="800" height="496"&gt;&lt;/a&gt;&lt;br&gt;
But this is not recommended. It's possible that many of the functions that we just called can fail, so we want to include a few more checks to make sure that everything is working correctly. Let's do that now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SDL_Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SDL_INIT_VIDEO&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;0&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;"Couldn't initialize SDL: %s&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="n"&gt;SDL_GetError&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;EXIT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;SDL_Window&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SDL_CreateWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Example: 0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SDL_WINDOWPOS_UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;SDL_WINDOWPOS_UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_HEIGHT&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;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;window&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;"Failed to open %d x %d window: %s&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="n"&gt;SCREEN_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SDL_GetError&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;EXIT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;SDL_Renderer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SDL_CreateRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_RenderClear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_Delay&lt;/span&gt;&lt;span class="p"&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;SDL_DestroyWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SDL_Quit&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;EXIT_SUCCESS&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;The first thing we do is call &lt;a href="https://wiki.libsdl.org/SDL2/SDL_Init"&gt;SDL_Init&lt;/a&gt; and pass the flag &lt;code&gt;SDL_INIT_VIDEO&lt;/code&gt;, which initializes the video subsystem. SDL has many initialization flags that you can bitwise OR (&lt;code&gt;|&lt;/code&gt;) together to initialize multiple subsystems at once. For example like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // Initialize SDL with video and audio subsystems
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
        printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
        return 1;
    } else {
        printf("SDL video and audio initialized successfully.\n");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we will stick to the video subsystem for now. Next we will call &lt;code&gt;SDL_CreateWindow&lt;/code&gt;. It takes in a title, x and y for the window position, width and height for the window size, and some flags. If we go to the wikipage for &lt;a href="https://wiki.libsdl.org/SDL2/SDL_CreateWindow"&gt;SDL_CreateWindow&lt;/a&gt; we will see the function prototype, a description of its parameters (including flags that can be passed), and the expected return values on failure. This is how I knew what that I wanted to pass &lt;code&gt;SDL_WINDOWPOS_UNDEFINED&lt;/code&gt; for the x and y, and let the operating system handle window placement.&lt;/p&gt;

&lt;p&gt;Moving on, we create our renderer with &lt;a href="https://wiki.libsdl.org/SDL2/SDL_CreateRenderer"&gt;SDL_CreateRenderer&lt;/a&gt;. We give it the window we created, so we can render to it, and pass its index parameter &lt;code&gt;-1&lt;/code&gt; to initialize the first rendering driver that can support our requested parameter flag of &lt;code&gt;0&lt;/code&gt;. You will always pass &lt;code&gt;-1&lt;/code&gt; as the &lt;strong&gt;index parameter&lt;/strong&gt; unless you have a good reason not to. For the &lt;strong&gt;render flag&lt;/strong&gt; we pass &lt;code&gt;0&lt;/code&gt; which defaults to &lt;code&gt;SDL_RENDERER_ACCELERATED&lt;/code&gt; (using hardware acceleration for the graphics) if it is supported on your system. If you want to be more explicit you can pass &lt;code&gt;SDL_RENDERER_ACCELERATED&lt;/code&gt; instead. Just like with the SDL window, we write an if statement to check if the renderer was created so that we don't accidentally use it if it hasn't been initialized.&lt;/p&gt;

&lt;p&gt;Next we call &lt;a href="https://wiki.libsdl.org/SDL2/SDL_SetRenderDrawColor"&gt;SDL_SetRenderDrawColor()&lt;/a&gt; and pass it our renderer, as well as 4 integers with values from 0-255. The 4 integers correspond to &lt;code&gt;Red&lt;/code&gt;, &lt;code&gt;Green&lt;/code&gt;, &lt;code&gt;Blue&lt;/code&gt;, and &lt;code&gt;Alpha&lt;/code&gt; values of a color. The alpha controls the transparency of the color, while setting the R, G, and B values to various levels allow you to create any color you want between &lt;code&gt;0,0,0,255&lt;/code&gt; (Black) and &lt;code&gt;255,255,255,255&lt;/code&gt; (White). &lt;a href="https://wiki.libsdl.org/SDL2/SDL_SetRenderClear"&gt;SDL_RenderClear()&lt;/a&gt; takes our renderer and clears it with the white color we set using &lt;code&gt;SDL_SetRenderDrawColor&lt;/code&gt;. &lt;a href="https://wiki.libsdl.org/SDL2/SDL_RenderPresent"&gt;SDL_RenderPresent()&lt;/a&gt; displays our graphics to the screen (just a white window for now) and then we call &lt;a href="https://wiki.libsdl.org/SDL2/SDL_Delay"&gt;SDL_Delay(2000)&lt;/a&gt; which specifies a number of milliseconds to wait before moving onto the next piece of code. Normally the rendering code will be in a while loop that will constantly update until the user quits the game, but for simplicities' sake, we will stick with a delay for now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wiki.libsdl.org/SDL2/SDL_DestroyWindow"&gt;SDL_DestroyWindow&lt;/a&gt; safely removes our window once we are done with it. If for whatever reason the window was not initialized, it is still safe to call this on the &lt;code&gt;window&lt;/code&gt; variable. The same goes for &lt;a href="https://wiki.libsdl.org/SDL2/SDL_DestroyRenderer"&gt;SDL_DestroyRenderer&lt;/a&gt;. It does the same thing as &lt;code&gt;SDL_DestroyWindow&lt;/code&gt; and cleans up our renderer. Finally we call &lt;a href="https://wiki.libsdl.org/SDL2/SDL_Quit"&gt;SDL_Quit&lt;/a&gt; which cleans up the systems we initialized before we close our program.&lt;/p&gt;

&lt;p&gt;And that is it, we've created our first window in SDL. In the next tutorial we will look at how to draw text on the screen.&lt;/p&gt;

&lt;p&gt;One last thing to note. I will not be abstracting many things to functions or multiple files in these first few tutorials. I believe it's important when you are learning a new library, to keep it as simple as possible. As the code gets longer this will become a bigger pain point, and that is good. You will have a much clearer picture about what we should abstract, and why we should abstract it, as you become more familiar with SDL. Feel free to come up with your own abstractions as you see fit&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why do we clear the screen with a color?
&lt;/h3&gt;

&lt;p&gt;We clear the screen with a color so that the previous frames pixels don't interfere with the next frames pixels. For example, if we have a square on the screen that we are moving with the &lt;code&gt;WASD&lt;/code&gt; keys, if we don't clear the screen, then square will smear across the screen as the old pixels from it's old position are not "wiped" away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why SDL and not Raylib?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.raylib.com/"&gt;Raylib&lt;/a&gt; is an awesome C library for creating games, and Raysan specifically made it for teaching. He did &lt;a href="https://gist.github.com/raysan5/17392498d40e2cb281f5d09c0a4bf798"&gt;a comparison&lt;/a&gt; at one point between the two frameworks, though it is a little dated at this point. It is easier to learn and make new FFI bindings for Raylib than it is for SDL and Raylib comes with more convenience features out of the box. You are not making a mistake if you choose Raylib. But SDL has been around over twice as long as Raylib. Many of the open source projects I'm interested in contributing to (Doom Source Ports, &lt;a href="https://gitlab.com/OpenMW/openmw"&gt;OpenMW&lt;/a&gt;, and others were started before Raylib existed and use SDl2. Since these projects use SDL so will I. SDL2 is also a little lower level than Raylib, and requires you to work at a lower level with it's subsystems. This means instead of placing drawing code between a &lt;code&gt;BeginDrawing&lt;/code&gt; and &lt;code&gt;EndDrawing&lt;/code&gt; block like in Raylib, you have to set up the renderer, create textures, copy them to the GPU, before finally presenting it to the screen. I find this process to be enlightening.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>programming</category>
      <category>c</category>
    </item>
    <item>
      <title>The continued rise of Handheld Gaming</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Thu, 08 Feb 2024 14:19:39 +0000</pubDate>
      <link>https://dev.to/deusinmachina/the-continued-rise-of-handheld-gaming-5hkf</link>
      <guid>https://dev.to/deusinmachina/the-continued-rise-of-handheld-gaming-5hkf</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmgjwbjuyef27ehhsy2tl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmgjwbjuyef27ehhsy2tl.jpg" alt="Ring toss Water Game" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My very first handheld game was probably the ring toss game… But in all seriousness it was my fathers Game Boy in the late 90s. I distinctly remember playing Star Wars and I don’t think I ever beat it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4hn6k9xsw49bpl8ekhj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4hn6k9xsw49bpl8ekhj.jpeg" alt="Original Game Boy" width="800" height="970"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2jlq7gceiww4x56f5g9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2jlq7gceiww4x56f5g9.png" alt="Star Wars for the Game Boy" width="800" height="676"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I remember handheld gaming being all the rage growing up, and I have fond memories of playing on Game Boys, Game Boy Colors, Game Boy Advances, PSPs, and DS'. Like many, after about the PSP era, I moved away from consoles and handhelds in favor of PCs. But since getting back into handheld gaming with my Steam Deck, I was shocked to see there had been a Cambrian explosion of handhelds. Many are from major players in the tech space, though some are from companies I've never heard of. It feels like we are in a renaissance, or, that is what I thought the angle of this article was going to be when I started writing it. But in actually researching handheld history, I've come to the conclusion that while I had abandoned it, it hadn't gone anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lightning Tour
&lt;/h2&gt;

&lt;p&gt;Let's take a look back at one of the earliest handhelds. For the sake of brevity I'll only consider handhelds that could play more than one game, so no Game and Watches, or single game electronics. In this vein the honor to the first handheld gaming console that fits our criteria is the Microvision created in 1979.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkratvbvy7ygshhmsj0co.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkratvbvy7ygshhmsj0co.jpg" alt="Microvision handheld device" width="800" height="1090"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looked more like the iClicker I had in College than a gaming device, but it had 12 different games that it could play. Clocking in on a CPU that ran at 1kHZ, a number I have never seen next to a CPU, It's honestly hugely impressive it could play anything. &lt;/p&gt;

&lt;p&gt;But just 10 years later we would be introduced to one of the most popular handhelds of all time, by one of handheld gaming's most prolific supporters, Nintendo. The Game Boy would be a smash hit, bringing handheld gaming to the masses. Nintendo has certainly not slowed down since then and if we look at the timeline from the Game Boy to the Switch we get a history that spans from 1989-2021 with no signs of stopping.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Game Boy&lt;/strong&gt;: Released on April 21, 1989, in Japan, July 31, 1989, in North America, and September 28, 1990, in Europe. The OG.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Game Boy Pocket&lt;/strong&gt;: Released in 1996, it was a smaller, lighter Game Boy that required fewer batteries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Game Boy Light&lt;/strong&gt;: Released only in Japan on April 14, 1998, this model featured a backlit screen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Game Boy Color&lt;/strong&gt;: Released on October 21, 1998, in Japan, November 18, 1998, in North America, and November 23, 1998, in Europe. Backwards compatible with the Game Boy! Contained a 15-bit color palette instead of the 4 in the original Game Boy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Game Boy Advance&lt;/strong&gt;: Released on March 21, 2001, in Japan, June 11, 2001, in North America, and June 22, 2001, in Europe. Backwards compatible again! Hardware that was more powerful than the SNES from a decade prior. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Game Boy Advance SP&lt;/strong&gt;: Released in February 2003, it featured a front-lit screen and a clamshell design.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Game Boy Micro&lt;/strong&gt;: Released on September 13, 2005, in Japan, and subsequently in other regions. A slimmer version of the original GBA.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo DS&lt;/strong&gt;: Released on November 21, 2004, in North America, December 2, 2004, in Japan, February 24, 2005, in Australia, and March 11, 2005, in Europe. Successor to and backwards compatible with the Game Boy Advance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo DS Lite&lt;/strong&gt;: Released in early 2006, it was a slimmer and lighter version of the original DS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo DSi&lt;/strong&gt;: Released on November 1, 2008, in Japan, and in 2009 in other regions. No slot for GBA Games. Two cameras, SD Card slot, and other enhancements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo DSi XL/LL&lt;/strong&gt;: Released in 2009, it was a DS that larger screens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo 3DS&lt;/strong&gt;: Released on February 26, 2011, in Japan, March 25, 2011, in Europe, March 27, 2011, in North America, and March 31, 2011, in Australia. Successor to the DS with the most notable feature being the 3d graphics, 3 cameras, and AR capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo 3DS XL&lt;/strong&gt;: Released in 2012, this version featured larger screens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo 2DS&lt;/strong&gt;: Released on October 12, 2013, as a budget version of the 3DS without 3D capability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;New Nintendo 3DS&lt;/strong&gt;: Released on October 11, 2014, in Japan, and 2015 in other regions. Enhanced performance, better 3d, a C-stick, and built in NFC.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;New Nintendo 3DS XL&lt;/strong&gt;: Released alongside the New Nintendo 3DS, with larger screens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;New Nintendo 2DS XL&lt;/strong&gt;: Released on July 13, 2017, as an upgraded version of the 2DS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo Switch&lt;/strong&gt;: Released on March 3, 2017, a hybrid console, usable as docked as a home console and undocked as a handheld device.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo Switch Lite&lt;/strong&gt;: Released on September 20, 2019, features non removeable joycons. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nintendo Switch OLED&lt;/strong&gt;: Released on October 8, 2021, it's a Switch, but with a nicer screen.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Phew! That was a lot. While compiling this list a couple of things became apparent to me.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Nintendo has been keeping the handheld dream alive, even after other hardware manufactures had left the space. &lt;/li&gt;
&lt;li&gt;Nintendo &lt;em&gt;loves&lt;/em&gt; to sell you the same handheld over and over again. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Multiple Game Boy's DS' and Switches. I wouldn't be surprised if we see a Switch XL at some point. And you already know there will be a Switch 2 Lite.&lt;/p&gt;

&lt;p&gt;But while Nintendo never stopped making Handhelds, the list of handhelds we got from 1989 to ~2013 ranged for weird, wacky, cool, and everything in between. Here are some of them &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Atari Lynx (1989)&lt;/strong&gt; - First handheld console with a color LCD screen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sega Game Gear (1990)&lt;/strong&gt; - Competitor to the Nintendo Game Boy, known for its backlit color screen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sega Nomad (1995)&lt;/strong&gt; - Handheld version of the Sega Genesis, allowing players to use Genesis cartridges.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tapwave Zodiac (2004)&lt;/strong&gt; - Short lived device that functioned as both a PDA and a gaming console.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sony PlayStation Portable (PSP) (2005)&lt;/strong&gt;- Known for its powerful hardware, multimedia capabilities, and wide game selection. I had one with a skin covered in green skulls, and it was incredible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GP2X Wiz (2009)&lt;/strong&gt; - An open-source, Linux-based handheld console produced by GamePark Holdings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pandora (2010)&lt;/strong&gt; - A combination of a handheld game console and a mini PC, running Linux.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sony PlayStation Vita (2012)&lt;/strong&gt; - Successor to the PSP. Featured a touch screen, rear touchpad, and high-quality graphics. Please bring it back Sony. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nvidia Shield Portable (2013)&lt;/strong&gt; - An Android-based device that combined a game controller with a screen, capable of streaming games from a PC.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjv9ru6izkn6fb22atjal.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjv9ru6izkn6fb22atjal.jpg" alt="Zodiac Tapwave raunchy advertisement" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One interesting thing to note about this time. With devices like the Nvidia Shield, we begin to see the rise of handheld streaming devices. This is a lot more common now with the likes of the PlayStation &lt;br&gt;
Portal, and Logitech G Cloud (with an honorable mention to the Steam Link).&lt;/p&gt;

&lt;p&gt;I would be remiss if I didn't at least talk about the most common forms of handheld gaming of our generation, mobile gaming. While I do remember playing games like Dragon's lair on my father's Sprint flip phone... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzn5pe0tpjoc13nd0m7ia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzn5pe0tpjoc13nd0m7ia.png" alt="Dragon's Lair video game" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was when we got smartphones where I really saw the quality of mobile gaming blow up. I remember games like Zenonia back in 2009 being awesome. I couldn't believe I was playing such a fully featured rpg right in the palm of my hand at that time. I remember sitting back and playing it for hours on my landscaped iPod in a wooden chair with no cushion, my back and eyes would never permit that now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifrasnvmtcyqnttzcqop.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifrasnvmtcyqnttzcqop.jpg" alt="Zenonia rpg mobile game" width="640" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was pre candy crush too, so the dark patterns were either non existent, or much simpler at the time. You could even buy a game once, and never pay for it again (shocking I know). And remember Infinity Blade? Mobile gaming may have truly peaked in 2010.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb6awo8yr5e102yqo3c1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb6awo8yr5e102yqo3c1.png" alt="Infinity Blade mobile game" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if we include phones on this tour, we'd be here all day so let's get back to dedicated handhelds. Not only have we had great handhelds for the last 35 years, if you look at the top 5 best selling consoles of all time...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;PlayStation 2 &lt;/li&gt;
&lt;li&gt;Nintendo DS &lt;/li&gt;
&lt;li&gt;Nintendo Switch &lt;/li&gt;
&lt;li&gt;Game Boy/Game Boy Color &lt;/li&gt;
&lt;li&gt;PlayStation 4&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We see that three out of the top 5 are actually handhelds. So with that fact, and with this article having mentioned over two dozen handheld devices at this point, It's safe to say handhelds, and handheld gaming, never went away. In fact I'd say it's more popular now that it has ever been! &lt;/p&gt;

&lt;p&gt;The experience is also so much better than it used to be. For one, I don't have to go through dozens of AA batteries a month anymore. And two, they don't feel cut down. Using my previously mentioned Star Wars Game Boy game as an example, I recently found out that this is what the NES version looked like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvusdwxguqgns36dtc53e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvusdwxguqgns36dtc53e.png" alt="NES color version of Star Wars" width="800" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Shocking! I would have loved to have my Game Boy version look like that back in the 90s. By the Game Boy Advanced era in 2001, we were able to create incredible 2D handheld experiences, but we were only just &lt;em&gt;getting&lt;/em&gt; to the point where we could render anything impressive in 3D. Sure you could program a 3D GBA game if you were a literal programming God like Randal Linden, but unless you are willing to write 200,000 lines of highly optimized assembly then we still needed a few generations before this was feasible for your average programmer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzy3lukupny7mpsjrmcte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzy3lukupny7mpsjrmcte.png" alt="Quake running on the Game Boy Advance" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But fast forward to the PSP era, and we were beginning to see what no compromise 3d handheld experiences looked like. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhoaekbg66px6vw5bsm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhoaekbg66px6vw5bsm2.png" alt="Tekken Dark Resurrection on the PSP" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And by the time we got to the Switch, it was clear that while certain games might have struggled to hit their 30fps target sometimes, we weren't getting stripped down version of a game originally made for PCs and consoles anymore. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjehx8epx0pjbn9amac6l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjehx8epx0pjbn9amac6l.jpg" alt="Breath of the wild" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now in the more modern times (a sentence that will age like milk) we see many other players in the space besides Sony and Nintendo. There are Android, Windows, and Linux based handhelds, some from well known brands, and others from rising stars...  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GPD XD&lt;/strong&gt;: 2015&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPD Win&lt;/strong&gt;: 2016&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPD XD Plus&lt;/strong&gt;: 2018 &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abernic RG351P&lt;/strong&gt;: 2020&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retroid Pocketc 2S&lt;/strong&gt;: 2020&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Miyoo Mini&lt;/strong&gt;: 2021 &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ayn Odin&lt;/strong&gt;: 2022&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Steam Deck&lt;/strong&gt;: 2022&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Miyoo Mini +&lt;/strong&gt;: 2023&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logitech G Cloud&lt;/strong&gt;: 2023 &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lenovo Legion Go&lt;/strong&gt;: 2023&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ayn Odin 2&lt;/strong&gt;: 2023&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asus Rog Ally&lt;/strong&gt;: 2023&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Steam Deck OLED&lt;/strong&gt;: 2023&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PlayStation Portal&lt;/strong&gt;: 2023 &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Msi Claw&lt;/strong&gt;: Sometime in 2024&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it's exciting. It feels like we've hit an inflection point with handhelds. With devices like my Steam Deck, I don't feel like I'm giving anything up when I'm using it. But at the same time, I'm excited for every new iteration. It feels just like how it was in the late 90s and 2000s where every console generation, or graphics card generation, was a noticeable improvement over the last. And with the Switch 2 rumored to be announced later this year, it seems like that excitement isn't going to be slowing down anytime soon. &lt;/p&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a &lt;a href="https://twitter.com/deusinmach"&gt;Twitter&lt;/a&gt; and a &lt;a href="https://mastodon.social/deck/@DiegoCrespo"&gt;Mastodon&lt;/a&gt;, if you’d like to follow me on other social media platforms. If you liked the article, consider checking out my &lt;a href="https://www.deusinmachina.net/"&gt;Substack&lt;/a&gt;. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.deusinmachina.net/p/the-evolution-of-valves-source-engine"&gt;https://www.deusinmachina.net/p/the-evolution-of-valves-source-engine&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gaming</category>
    </item>
    <item>
      <title>Geek Mythology: The Religious, and Spiritual Folklore surrounding Programming</title>
      <dc:creator>Diego Crespo</dc:creator>
      <pubDate>Mon, 12 Jun 2023 01:06:50 +0000</pubDate>
      <link>https://dev.to/deusinmachina/geek-mythology-the-religious-and-spiritual-folklore-surrounding-programming-51pf</link>
      <guid>https://dev.to/deusinmachina/geek-mythology-the-religious-and-spiritual-folklore-surrounding-programming-51pf</guid>
      <description>&lt;p&gt;The word of the day is religionization. According to the Merriam-Webster dictionary it means…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;to make religious : imbue with religious principles : bring into conformity with religious standards : interpret or understand (a thing) from a religious framework&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I first started learning how to program I was surprised at how much religious, spiritual, and folklore surrounded it. I mean this is computers! Shouldn’t it all just be rational and logical? Turns out this isn’t the case, and some people have taken this concept to the extreme building entire &lt;a href="https://en.wikipedia.org/wiki/TempleOS"&gt;Operating Systems based on their faith&lt;/a&gt;. Let’s look at some notable examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Usenet Holy Wars ⚔️
&lt;/h2&gt;

&lt;p&gt;Conceived in 1978 Usenet was the precursor to the internet. It allowed people to communicate over a distributed network of computers. Users could read and post messages on Newsgroups for a wide variety of topics. When it was first created it was only used by graduate students and academics. But as it grew in popularity more and more people used it to discuss things outside of academia, including favorite T.V shows, movies, games, and software tools. This would ultimately lead to the Usenet Holy Wars as they are now known. Emacs vs Vi/Vim, BSD vs Linux, Tabs vs Spaces, &lt;a href="https://wiki.c2.com/?HolyWar"&gt;the list goes on and on&lt;/a&gt;. Programmers have had their preferences since the age of computing. But beyond simple preferences, &lt;a href="https://wiki.c2.com/?PersonalChoiceElevatedToMoralImperative"&gt;there are those who elevate their personal choices to moral imperatives&lt;/a&gt;. When this happens, emotions run high, rationality gets left at the door, and ad hominem attacks become the norm. One of the most famous examples comes from our &lt;a href="https://groups.google.com/g/comp.os.minix/c/wlhw16QWltI/m/P8isWhZ8PJ8J"&gt;Favorite Finnish Flamer Linus Torvalds himself over Linux vs Minix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The connection is obvious here. Humans have been fighting over belief for as long as there have been two competing religions within close proximity of each other. It’s only natural that with wide variety of software and tools that programmers would become just as passionate. My only hope is that unlike the crusades, no blood has ever been shed over someones personal choices in software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mysticism 🔮
&lt;/h2&gt;

&lt;p&gt;A Koan is a Zen Buddhist story, question, or dialogue that is told to provoke a deeper understanding of a subject. Many programmers count themselves as Zen Buddhists. Whether due to the stress of Silicon Valley, or the insanity that comes from trying to speak to something as unfeeling or unforgiving as a computer, that drives them to Buddhism, I’m not sure. My first experience with Koans was with &lt;a href="https://www.emacswiki.org/emacs/EmacsKoans"&gt;Emacs Koans&lt;/a&gt; very early on in my programming career. My favorite one is this…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In vain does the chicken cross the road; Emacs is on both sides. – Ludovic Brenta.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Programming parlance has adopted this terminology and it goes one of two ways. Like an ancient proverb as in the above example, or as a set of small problems that allow deeper understanding of a specific programming concept. This is how the &lt;a href="https://www.rubykoans.com/"&gt;ruby koans&lt;/a&gt; website works, with thirty different ruby problems designed to help you practice the test driven development methodology.&lt;/p&gt;

&lt;p&gt;Sticking with Eastern philosophy we have websites like &lt;a href="http://www.canonical.org/~kragen/tao-of-programming.html"&gt;The Tao Of Programming&lt;/a&gt;. With tongue and cheek snippets spread out over 9 “books” it gives insights into the act of programming. My favorite of which is…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Tao gave birth to machine language. Machine language gave birth to the assembler.&lt;br&gt;
The assembler gave birth to the compiler. Now there are ten thousand languages.&lt;br&gt;
Each language has its purpose, however humble. Each language expresses the Yin and Yang of software. Each language has its place within the Tao.&lt;br&gt;
But do not program in COBOL if you can avoid it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This mystification of the way we interact with computers reminds me of the religious naturalism that is seen in the way many people react to the natural world. But the similarities don’t stop there. We have “Bibles” which are books that are considered authoritative on their subject. Many times they aren’t even referred to by their actual names but by their covers or who wrote them, as if the names themselves are sacred. Examples like “The Red Book” for the The OpenGL Programming Guide, “K&amp;amp;R” for &lt;em&gt;The C Programming Language&lt;/em&gt;, “The Wizard book”, or “SCIP” for &lt;em&gt;Structure and Interpretation of Computer Programs&lt;/em&gt;, and “The Dragon book” for &lt;em&gt;Compilers: Principles, Techniques, and Tools&lt;/em&gt;. These books have had deep cultural impacts on the programmers that grew up reading them, and they are treated appropriately.&lt;/p&gt;

&lt;p&gt;And it is not just books. The Lisp programming language has also taken on a mystical quality. Something not seen in other programming languages developed in that era. A famous XKCD comic describes the feeling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P4p4_knj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eu577rbw3sp0rryldszs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4p4_knj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eu577rbw3sp0rryldszs.png" alt="lisp parenthesis xkcd" width="640" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Faith 🙏
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BTOMj2Fn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwrv4yim7lcxciqp685n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BTOMj2Fn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwrv4yim7lcxciqp685n.png" alt="Meme about only god understanding the code." width="600" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hardware and Software are complex, and whether you call the trust you put into compilers, and computers that run your code faith or something, else it’s hard to deny that at times they can appear magical. There was a time where computers were simple enough that one person could know the whole thing inside and out. That they could solder every component themselves and truly build everything from scratch. If you are &lt;a href="https://www.youtube.com/watch?v=HyznrdDSSGM&amp;amp;list=PLowKtXNTBypGqImE405J2565dvjafglHU"&gt;Ben Eater you still can&lt;/a&gt;. Even though computers are complex I don't think that's an excuse not to learn more about them. I attempted this on a small scale with the &lt;a href="https://docs.google.com/document/d/138KRMrkH2S51Geb1TsguTKgYEwfh9TlrAk5n-ILYFw8/edit?usp=sharing"&gt;Raspberry PI 4&lt;/a&gt;, challenging myself to understand how the hardware works on it. But even the best of us's knowledge breaks down somewhere in the computer -&amp;gt; hardware pipeline, and we just have to take things on faith. God knows how many millions of lines of code have to be executed from the time I press a key on my keyboard, to the time the next character appears in this web browser. It's amazing that it works at all, and I'm grateful I don't need to understand all of it for it to keep working. Sometimes when I'm coding I like to think about all the things I put my faith into.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;That the compiler will compile my code properly&lt;/li&gt;
&lt;li&gt;That the Operating System will interact with my program the way I want it to&lt;/li&gt;
&lt;li&gt;That the machine code will excite the necessary transistors to do the work in the processor I need it to do&lt;/li&gt;
&lt;li&gt;That turning my computer on and off just fixes things sometimes&lt;/li&gt;
&lt;li&gt;That the libraries I’m using don’t have back doors that will steal all my data&lt;/li&gt;
&lt;li&gt;and on and on and on&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I know it’s not magic, but it certainly feels like it. And there are still things like &lt;a href="https://en.wikipedia.org/wiki/Soft_error"&gt;soft errors&lt;/a&gt;, and a whole list of &lt;a href="https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processor-specification-update/errata-details/"&gt;hardware errata&lt;/a&gt; that seeks to thwart your understanding. This is on top of our varying ability to keep large chunks of programs in our head while reading code. Sometimes the code is doing something particular complex or obtuse, and even when it's actually written by a fellow human being, it’s not always clear what exactly is going on. My favorite quote about this is…&lt;br&gt;
&lt;code&gt;317:     /*&lt;br&gt;
 318:    * If the new process paused because it was&lt;br&gt;
 319:    * swapped out, set the stack level to the last call&lt;br&gt;
 320:    * to savu(u_ssav).  This means that the return&lt;br&gt;
 321:    * which is executed immediately after the call to aretu&lt;br&gt;
 322:    * actually returns from the last routine which did&lt;br&gt;
 323:    * the savu.&lt;br&gt;
 324:    *&lt;br&gt;
 325:    * You are not expected to understand this.&lt;br&gt;
 326:    */&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Line 325 is so famous, there is an entire book whose &lt;a href="https://www.amazon.com/You-Are-Expected-Understand-This-ebook/dp/B0B1S2PDWV/ref=sr_1_1?keywords=you+are+not+expected+to+understand+this+book&amp;amp;qid=1673822537&amp;amp;sprefix=you+are+not+expec%2Caps%2C360&amp;amp;sr=8-1"&gt;title is this quote&lt;/a&gt;. Thankfully more often than not we don't need to know everything when programming. We can usually take a programming lesson from Alan Knight's quote about Object Oriented programming when working in foreign code bases.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Try not to care.&lt;br&gt;
One of the great leaps in OO is to be able to answer&lt;br&gt;
the question "How does this work?" with "I don’t care".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With it becoming more common for AI to write code, I fear a reality where the majority of code that is written is not by humans, and not understandable by humans. Kind of like languages that transpile to C instead of machine code first. The feeling is captured in this meme…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dZa2odlH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9dhxfo6lmu2vpwgd87m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dZa2odlH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9dhxfo6lmu2vpwgd87m.png" alt="joke about chatgpt ruining our understanding of code" width="543" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Folklore🪕
&lt;/h2&gt;

&lt;p&gt;Finally there is a lot of folklore surrounding programming. There is literally a website called &lt;a href="https://www.folklore.org/index.py"&gt;folklore&lt;/a&gt; which documents the stories of the development of the original Macintosh, and spins yarns of programming aptitude I will never reach. My favorite probably being the &lt;a href="https://www.folklore.org/StoryView.py?story=Negative_2000_Lines_Of_Code.txt"&gt;-2000 Lines Of Code&lt;/a&gt;&lt;br&gt;
story. If you are blessed enough to be immortalized in one those stories you become one of the gods in the programming pantheon. Eric Raymond describes a few in his &lt;a href="https://www.linuxjournal.com/article/3882"&gt;Why Python?&lt;/a&gt; blog post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Larry Wall, its creator, is rightly considered one of the most important leaders in the Open Source community, and often ranks third behind Linus Torvalds and Richard Stallman in the current pantheon of hacker demigods.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not everyone agrees to who belongs in the pantheon, but for them there are fictional hackers, like Mel &lt;a href="https://groups.google.com/g/net.jokes/c/k2JVKQzJSpY"&gt;“The Realest Programmer of them All”&lt;/a&gt;. Mel the programmer who chose not to have faith in compilers, and hand optimized all of his own code. Mel whose mastery of bit fiddling allowed him to achieve performance not though possible on any hardware he touched. Even today's elite programmers would bow at the feet of Mel's accomplishments. Go read the story it's definitely worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping it all up 🎁
&lt;/h2&gt;

&lt;p&gt;Programming is suffused with religious mysticism. Like the West African griots, we tell the stories of our history through metaphor, parables, and folklore. We ask our machine learning models questions like they are the &lt;a href="https://www.deusinmachina.net/p/the-fascinating-development-of-ai-47b"&gt;Oracle of Delphi&lt;/a&gt;. We take our actual faith and ask What would Jesus do? &lt;a href="http://www.geero.net/2008/02/programming_for_christ/"&gt;if he were programming.&lt;/a&gt; We borrow terms like Daemon, we have &lt;a href="https://www.linkedin.com/in/jeffbarr/"&gt;Chief “Evangelists”&lt;/a&gt; who spread the good word about our programming languages and software.&lt;/p&gt;

&lt;p&gt;One thing is clear to me, there is a lot more humanity in the field of programming than people like to let on. Our Geek Mythology is still being written, and it inspires us, makes us laugh, and motivates us to achieve greater heights in the field. As I wrap up this article I’d like to leave you with one more quote. It’s from Proverbs 16:3…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Commit to &lt;del&gt;the Lord&lt;/del&gt; GitHub whatever you do, and your plans will succeed."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Call To Action 📣
&lt;/h2&gt;

&lt;p&gt;If you made it this far thanks for reading! If you are new welcome! I like to talk about technology, niche programming languages, AI, and low-level coding. If this interests you there's more where that came from on &lt;a href="https://www.deusinmachina.net/"&gt;my Substack&lt;/a&gt;. I’ve recently started a &lt;a href="https://twitter.com/deusinmach"&gt;Twitter&lt;/a&gt; and would love for you to check it out. I also have a &lt;a href="https://mastodon.social/@DiegoCrespo"&gt;Mastodon&lt;/a&gt; if that is more your jam. If you liked the article, consider liking and subscribing. And if you haven’t why not check out another article of mine! Thank you for your valuable time.&lt;/p&gt;

</description>
      <category>society</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
