<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[C Game Dev]]></title><description><![CDATA[Engine programmer. Prev Head of Engineering at Proxima and Senior Engineer at Unity. Built @playsuckup ($1M+), now building the next generation 3D engine technology.]]></description><link>https://posts.cgamedev.com</link><image><url>https://substackcdn.com/image/fetch/$s_!5VxF!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6ad370f-0134-49dd-809f-de02f9c3d80b_200x200.png</url><title>C Game Dev</title><link>https://posts.cgamedev.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 08 May 2026 15:55:01 GMT</lastBuildDate><atom:link href="https://posts.cgamedev.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Gabriel Dechichi]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[cgamedev@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[cgamedev@substack.com]]></itunes:email><itunes:name><![CDATA[dechichi]]></itunes:name></itunes:owner><itunes:author><![CDATA[dechichi]]></itunes:author><googleplay:owner><![CDATA[cgamedev@substack.com]]></googleplay:owner><googleplay:email><![CDATA[cgamedev@substack.com]]></googleplay:email><googleplay:author><![CDATA[dechichi]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Random thoughts on AI and self-education]]></title><description><![CDATA[and why I haven't posted in a while]]></description><link>https://posts.cgamedev.com/p/random-thoughts-on-ai-and-self-education</link><guid isPermaLink="false">https://posts.cgamedev.com/p/random-thoughts-on-ai-and-self-education</guid><dc:creator><![CDATA[dechichi]]></dc:creator><pubDate>Thu, 12 Feb 2026 17:44:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3zWy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>It&#8217;s been a while since my last article, and my plan was to go in-depth on implementing threads on WASM. But company work has been getting in the way. In the meantime, I had some random thoughts I felt like sharing.</em></p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3zWy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3zWy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 424w, https://substackcdn.com/image/fetch/$s_!3zWy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 848w, https://substackcdn.com/image/fetch/$s_!3zWy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!3zWy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3zWy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg" width="1500" height="864" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:864,&quot;width&quot;:1500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:324285,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://posts.cgamedev.com/i/187767257?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaf3f236-72f0-4b74-9672-fd61c6226b9d_1500x1350.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3zWy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 424w, https://substackcdn.com/image/fetch/$s_!3zWy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 848w, https://substackcdn.com/image/fetch/$s_!3zWy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!3zWy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb88c7dd-c520-4158-9563-cf1071c13e49_1500x864.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I&#8217;m often critical of AI around here, mostly as a response to the overhyped promises (a.k.a. lies) many people post. That said, I think the technology itself is remarkable.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://posts.cgamedev.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">C Game Dev is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>One thing I&#8217;m noticing is that more people are building game engines (actual game developers, not tech bros).</p><p>Maybe similar to how Google unlocked more access to information, AI might be unlocking it even more by making this information digestible to beginners.</p><p>When I first started studying graphics, I picked up Graphics Programming with DirectX 9 - Part 1. It&#8217;s a 1000-page book. It wasn&#8217;t easy nor fun to read, and it was especially hard not having anyone to ask clarification questions to. I think my past self would have enjoyed being able to ask AI to break down some of these concepts, ask why things weren&#8217;t compiling, what the application of X is, and so on.</p><p>One might say that the difficulty I experienced is part of learning, and making it easier would make me learn less, but I disagree. There is an optimal &#8220;difficulty setting&#8221; for learning, which varies from person to person and by experience level. If you can have a teacher when starting out, it&#8217;s extremely beneficial, and many people don&#8217;t have access to a private tutor.<br><br>The internet was a massive unlock by making information publicly accessible, AI might help it more by making this information digestible.<br><br>So maybe like me you don&#8217;t want to use AI for <em>programming</em> (you want to <em>actually</em> be able to do it yourself), but you might like using AI for <em>learning</em>.</p><p>What do you think of the above? Have you tried using AI this way? I would genuinely want to know.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://posts.cgamedev.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">C Game Dev is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The Hidden Cost of Software Libraries]]></title><description><![CDATA[and an argument for writing your own code]]></description><link>https://posts.cgamedev.com/p/the-hidden-cost-of-software-libraries</link><guid isPermaLink="false">https://posts.cgamedev.com/p/the-hidden-cost-of-software-libraries</guid><dc:creator><![CDATA[dechichi]]></dc:creator><pubDate>Wed, 22 Oct 2025 01:49:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!erAP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!erAP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!erAP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 424w, https://substackcdn.com/image/fetch/$s_!erAP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 848w, https://substackcdn.com/image/fetch/$s_!erAP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 1272w, https://substackcdn.com/image/fetch/$s_!erAP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!erAP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png" width="606" height="435.830303030303" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:712,&quot;width&quot;:990,&quot;resizeWidth&quot;:606,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Dependency Hell&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Dependency Hell" title="The Dependency Hell" srcset="https://substackcdn.com/image/fetch/$s_!erAP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 424w, https://substackcdn.com/image/fetch/$s_!erAP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 848w, https://substackcdn.com/image/fetch/$s_!erAP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 1272w, https://substackcdn.com/image/fetch/$s_!erAP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F797791ff-60c5-466e-8315-d74cf22f94b0_990x712.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Introduction</strong></h2><p>So the other day, I had this argument on X that inspired me to write about the cost of using libraries.</p><p>By &#8220;libraries&#8221; I mean that thing most of us are addicted to using these days, where you go to your package manager, type <code>npm install {something}</code>, and <code>{something}</code> magically pops into your project, giving you &#8220;incredible&#8221; new functionality for basically zero cost.</p><p>But is it really <em>zero cost</em>?</p><h2>How it started</h2><p>Recently I shared a <a href="https://x.com/gdechichi/status/1979220994305986794">screenshot of my command-line</a> API on X in response to a post criticizing an OOP pattern that created an entire class hierarchy just to parse the command-line.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6K_X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6K_X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 424w, https://substackcdn.com/image/fetch/$s_!6K_X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 848w, https://substackcdn.com/image/fetch/$s_!6K_X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 1272w, https://substackcdn.com/image/fetch/$s_!6K_X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6K_X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png" width="405" height="456.37420718816065" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:473,&quot;resizeWidth&quot;:405,&quot;bytes&quot;:206199,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://cgamedev.substack.com/i/176758746?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6K_X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 424w, https://substackcdn.com/image/fetch/$s_!6K_X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 848w, https://substackcdn.com/image/fetch/$s_!6K_X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 1272w, https://substackcdn.com/image/fetch/$s_!6K_X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fdd516f-d14a-4ef6-bc8b-1c4d8ccbef86_473x533.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Then this random guy re-shared the post with <a href="https://x.com/HSVSphere/status/1979229918597665203">his comments</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ta2C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ta2C!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 424w, https://substackcdn.com/image/fetch/$s_!ta2C!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 848w, https://substackcdn.com/image/fetch/$s_!ta2C!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 1272w, https://substackcdn.com/image/fetch/$s_!ta2C!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ta2C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png" width="596" height="197" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:197,&quot;width&quot;:596,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49470,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://cgamedev.substack.com/i/176758746?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ta2C!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 424w, https://substackcdn.com/image/fetch/$s_!ta2C!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 848w, https://substackcdn.com/image/fetch/$s_!ta2C!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 1272w, https://substackcdn.com/image/fetch/$s_!ta2C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea69887f-9598-4349-9bc6-68d3e98568c3_596x197.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>It seemed to me like an open-minded comment from someone clearly ready to have an intellectual discussion, so I decided to engage.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BdzD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BdzD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 424w, https://substackcdn.com/image/fetch/$s_!BdzD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 848w, https://substackcdn.com/image/fetch/$s_!BdzD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 1272w, https://substackcdn.com/image/fetch/$s_!BdzD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BdzD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png" width="592" height="100" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad4bc218-be59-4264-b022-cf8724945e4d_592x100.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:100,&quot;width&quot;:592,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18699,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://cgamedev.substack.com/i/176758746?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BdzD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 424w, https://substackcdn.com/image/fetch/$s_!BdzD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 848w, https://substackcdn.com/image/fetch/$s_!BdzD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 1272w, https://substackcdn.com/image/fetch/$s_!BdzD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad4bc218-be59-4264-b022-cf8724945e4d_592x100.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And he did! He sent <a href="https://x.com/HSVSphere/status/1979313564293959714">this</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Wwpr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Wwpr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 424w, https://substackcdn.com/image/fetch/$s_!Wwpr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 848w, https://substackcdn.com/image/fetch/$s_!Wwpr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 1272w, https://substackcdn.com/image/fetch/$s_!Wwpr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Wwpr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png" width="601" height="696" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:696,&quot;width&quot;:601,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:289747,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://cgamedev.substack.com/i/176758746?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Wwpr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 424w, https://substackcdn.com/image/fetch/$s_!Wwpr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 848w, https://substackcdn.com/image/fetch/$s_!Wwpr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 1272w, https://substackcdn.com/image/fetch/$s_!Wwpr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc4f187e-a58d-4f10-852c-2299a54aa523_601x696.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Following up with the affirmation that <em>&#8220;nothing else can beat it&#8221;.</em> Strong statements, he must really know what he&#8217;s talking about!</p><p>I&#8217;ll spare you the rest of the posts, as no discussion actually took place, but it made me think about how a reasonable discussion about the pros and cons of using libraries would <em>actually</em> go.</p><h2>The Good</h2><p>To start, the HSVSphere guy kinda has a point. It&#8217;s kinda nice to just define macros on top of a struct and get type-safe arguments. I&#8217;d argue it&#8217;s &#8220;clean&#8221; as well, in the sense that you can look at this struct and see every argument your program supports.</p><pre><code>#[derive(Parser, Clone)]
enum Command {
    Build,
}

#[derive(Parser, Clone)]
struct Args {
    #[clap(subcommand)]
    command: Option&lt;Command&gt;,

    #[clap(long)]
    debug: bool,

    #[clap(long)]
    release: bool,

    #[clap(long)]
    output: Option&lt;String&gt;,
}</code></pre><p>It&#8217;s definitely <em>also</em> nice to get a library that &#8220;just works&#8221; in exchange for a few seconds typing <code>cargo add clap</code> to install it.</p><p>Seems like a no-brainer, so why did I roll out my own command-line parsing code instead?</p><p>Well, because command-line parsing is trivial, and the costs of using a library to solve this problem far outweigh the benefits.</p><p></p><h2>The costs</h2><p><em>What are the costs you ask?</em></p><p>I&#8217;ll go over them below. But first, it&#8217;s worth pointing out what an engineer is responsible for when writing software. You might think it&#8217;s a long list, but it&#8217;s not.</p><div class="pullquote"><p><em>A software engineer is responsible for the compiled executable, running on the target hardware.</em></p></div><p>That&#8217;s it.</p><p>Notice that there is nothing here about code. Code is the means through which we generate the executable&#8212;the actual useful thing that runs on the actual hardware doing actual work. You could be writing C, Rust, Python, or x86 Assembly; it doesn&#8217;t matter.</p><p>Therefore, an engineer worth their salary should be thinking not just about how to save time when writing a piece of code, but also about the hardware cost of running this code (energy spent, server cost, bandwidth cost, etc.) and its impact on the end user (runtime speed, stability, memory usage, etc.).</p><p>With this in mind, here are the costs of using <a href="https://github.com/clap-rs/clap">clap</a> for parsing command-line arguments</p><h2>Executable Size</h2><p>This is a Hello World program in C and its executable size:</p><pre><code>#include &lt;stdio.h&gt;

int main() {
    printf(&#8221;Hello, World!\n&#8221;);
    return 0;
}</code></pre><pre><code>time clang -O3 main.c -o main &amp;&amp; ./main build --debug --output o.exe &amp;&amp; ls -l main
clang -O3 main.c -o main  0.08s user 0.04s system 122% cpu 0.100 total
Hello, World!
-rwxr-xr-x@ 1 gabrieldechichi  staff  <strong>33432</strong> Oct 20 20:06 main</code></pre><p>And this is the equivalent Rust program and its executable size:</p><pre><code>fn main() {
    println!(&#8221;Hello, world!&#8221;);
}</code></pre><pre><code>cargo run --release &amp;&amp; ls -l target/release/cmdline_example
   Compiling cmdline_example v0.1.0
    Finished `release` profile [optimized] target(s) in 0.18s
     Running `target/release/cmdline_example`
Hello, world!
-rwxr-xr-x@ 1 gabrieldechichi  staff  <strong>468656</strong> Oct 20 19:29 target/release/cmdli
ne_example</code></pre><p>Without going into why the Rust build is somehow 469 KB, the question is: how much of an increase in executable size is parsing the command line worth?</p><p><em>1 KB? 10 KB? 1000 KB? 1,000,000 KB?</em></p><p>This might sound like a stupid question at first, but there is a limit. If I told you my amazing command-line library was 1 GB in size, you would probably look elsewhere.</p><div><hr></div><p>Let&#8217;s start with the C example. I&#8217;ve copy-pasted the <code>cmd_line.c</code> and <code>memory.c</code> implementations from my engine, with some small modifications. The files are attached for anyone interested in looking at the code behind the API.</p><pre><code>#include &lt;stdio.h&gt;
#include &#8220;memory.c&#8221;
#include &#8220;cmd_line.c&#8221;

int main(int argc, char *argv[]) {
  size_t buffer_size = 64 * 1024;
  u8 *buffer = calloc(1, buffer_size);
  ArenaAllocator arena = arena_from_buffer(buffer, buffer_size);

  CmdLineParser parser = cmdline_create(&amp;arena);

  // Register cmds
  cmdline_add_command(&amp;parser, &#8220;build&#8221;);
  cmdline_add_flag(&amp;parser, &#8220;debug&#8221;);
  cmdline_add_flag(&amp;parser, &#8220;release&#8221;);
  cmdline_add_option(&amp;parser, &#8220;output&#8221;);

  if (!cmdline_parse(&amp;parser, argc, argv)) {
    return 1;
  }

  if (cmdline_has_command(&amp;parser, &#8220;build&#8221;)) {
    printf(&#8221;Building project&#8221;);
    if (cmdline_has_flag(&amp;parser, &#8220;release&#8221;)) {
      printf(&#8221; in release mode&#8221;);
    } else if (cmdline_has_flag(&amp;parser, &#8220;debug&#8221;)) {
      printf(&#8221; in debug mode&#8221;);
    }
    printf(&#8221;...\n&#8221;);

    const char *out = cmdline_get_option(&amp;parser, &#8220;output&#8221;);
    if (out) {
      printf(&#8221;Output will be written to: %s\n&#8221;, out);
    }
  }

  return 0;
}</code></pre><pre><code>time clang -O3 main_cmdline.c -o main &amp;&amp; ./main build --debug --output o.exe &amp;&amp; ls -l main
clang -O3 main_cmdline.c -o main  0.08s user 0.04s system 105% cpu 0.123 total
Building project in debug mode...
Output will be written to: o.exe
-rwxr-xr-x@ 1 gabrieldechichi  staff  <strong>35224</strong> Oct 20 20:06 main</code></pre><p>As you can see, my <code>cmd_line.c</code> implementation added 1.79 KB to the release executable. Honestly, this is more than I expected, but I guess it makes sense given I&#8217;m also adding the <code>memory.c</code> implementation and the standard library functions it depends on into the mix. (I really want to get rid of the standard library someday.)</p><p>What about <a href="https://github.com/clap-rs/clap">clap</a>? Glad you asked!</p><pre><code>use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command()]
struct Cli {
    #[command(subcommand)]
    command: Option&lt;Commands&gt;,
}

#[derive(Subcommand)]
enum Commands {
    Build {
        #[arg(long)]
        debug: bool,

        #[arg(long)]
        release: bool,

        #[arg(long)]
        output: Option&lt;String&gt;,
    },
}

fn main() {
    let cli = Cli::parse();

    match &amp;cli.command {
        Some(Commands::Build { debug, release, output }) =&gt; {
            print!(&#8221;Building project&#8221;);

            if *release {
                print!(&#8221; in release mode&#8221;);
            } else if *debug {
                print!(&#8221; in debug mode&#8221;);
            }

            println!(&#8221;...&#8221;);

            if let Some(out) = output {
                println!(&#8221;Output will be written to: {}&#8221;, out);
            }
        }
        None =&gt; {
            // No command provided
        }
    }
}</code></pre><pre><code>cargo run --release -- build --debug --output o.c &amp;&amp; ls -l target/release/cmdline_example
   Compiling proc-macro2 v1.0.101
   Compiling unicode-ident v1.0.19
   Compiling quote v1.0.41
   Compiling utf8parse v0.2.2
   Compiling colorchoice v1.0.4
   Compiling anstyle v1.0.13
   Compiling anstyle-query v1.1.4
   Compiling is_terminal_polyfill v1.70.1
   Compiling clap_lex v0.7.6
   Compiling heck v0.5.0
   Compiling anstyle-parse v0.2.7
   Compiling strsim v0.11.1
   Compiling anstream v0.6.21
   Compiling clap_builder v4.5.50
   Compiling syn v2.0.107
   Compiling clap_derive v4.5.49
   Compiling clap v4.5.50
   Compiling cmdline_example v0.1.0 (/Users/gabrieldechichi/d
ev/src/github.com/gabrieldechichi/cgamedev-articles/251020-li
brary-costs/rust)
    Finished `release` profile [optimized] target(s) in 3.22s
     Running `target/release/cmdline_example build --debug --output o.c`
Building project in debug mode...
Output will be written to: o.c
-rwxr-xr-x@ 1 gabrieldechichi  staff  <strong>995296</strong> Oct 20 19:51 target/release/cmdline_example</code></pre><p>A *<em>whopping*</em> 527 KB added to the executable&#8212;just to parse a couple of strings. We barely have a program yet, and we&#8217;re almost at 1 MB for the optimized build.</p><p>To give you a sense of how wasteful this is, the ROM size for Super Mario 64 is between 6 and 8 MB depending on the region. That&#8217;s for a complete 3D game, including assets, 18 levels, and at least 20 hours of gameplay. Mario reasons about the costs!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jn8l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jn8l!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!jn8l!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!jn8l!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!jn8l!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jn8l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg" width="487" height="341.08949416342415" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1028,&quot;resizeWidth&quot;:487,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jn8l!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!jn8l!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!jn8l!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!jn8l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03f8711d-75f1-494b-b599-6d4e677b5af5_1028x720.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p>You might be thinking I&#8217;m micro-optimizing here. What is 500 KB at current download speeds?</p><p>Although this might be true (500 KB is significant for many applications), in practice it&#8217;s never one library, right? It&#8217;s usually dozens, each with its own dependencies, adding unnecessary bloat to the application. A few KB here and there, and soon your ChatGPT clone turns into a 250 MB executable.</p><p>If you think I&#8217;m making this up, just google &#8220;trending repositories javascript&#8221; and pick the first one on the list. On the day I&#8217;m writing this article it&#8217;s <a href="https://github.com/koodo-reader/koodo-reader/">koodo-reader</a>. Take a look at it&#8217;s <a href="https://github.com/koodo-reader/koodo-reader/blob/master/package.json">package.json</a></p><pre><code>(...)
&#8220;dependencies&#8221;: {
    &#8220;@aws-sdk/client-s3&#8221;: &#8220;^3.485.0&#8221;,
    &#8220;adm-zip&#8221;: &#8220;^0.5.2&#8221;,
    &#8220;axios&#8221;: &#8220;^0.19.2&#8221;,
    &#8220;basic-ftp&#8221;: &#8220;^5.0.5&#8221;,
    &#8220;better-sqlite3&#8221;: &#8220;^11.6.0&#8221;,
    &#8220;buffer&#8221;: &#8220;^6.0.3&#8221;,
    &#8220;chardet&#8221;: &#8220;^2.0.0&#8221;,
    &#8220;copy-text-to-clipboard&#8221;: &#8220;^2.2.0&#8221;,
    &#8220;dompurify&#8221;: &#8220;^3.2.4&#8221;,
    &#8220;electron-is-dev&#8221;: &#8220;^1.1.0&#8221;,
    &#8220;electron-store&#8221;: &#8220;^8.0.1&#8221;,
    &#8220;fflate&#8221;: &#8220;^0.8.2&#8221;,
    &#8220;file-saver&#8221;: &#8220;^2.0.5&#8221;,
    &#8220;form-data&#8221;: &#8220;^4.0.2&#8221;,
    &#8220;fs-extra&#8221;: &#8220;^9.1.0&#8221;,
    &#8220;hammerjs&#8221;: &#8220;^2.0.8&#8221;,
    &#8220;howler&#8221;: &#8220;^2.2.3&#8221;,
    &#8220;js-untar&#8221;: &#8220;^2.0.0&#8221;,
    &#8220;jszip&#8221;: &#8220;^3.10.1&#8221;,
    &#8220;localforage&#8221;: &#8220;^1.10.0&#8221;,
    &#8220;mammoth&#8221;: &#8220;^1.8.0&#8221;,
    &#8220;marked&#8221;: &#8220;^15.0.11&#8221;,
    &#8220;megajs&#8221;: &#8220;1.3.9-next.17&#8221;,
    &#8220;mhtml2html&#8221;: &#8220;^3.0.0&#8221;,
    &#8220;node-machine-id&#8221;: &#8220;^1.1.12&#8221;,
    &#8220;qs&#8221;: &#8220;^6.11.2&#8221;,
    &#8220;rangy&#8221;: &#8220;1.3.0&#8221;,
    &#8220;react-hot-toast&#8221;: &#8220;^2.1.1&#8221;,
    &#8220;react-sortablejs&#8221;: &#8220;^6.1.4&#8221;,
    &#8220;react-tooltip&#8221;: &#8220;^5.28.0&#8221;,
    &#8220;sortablejs&#8221;: &#8220;^1.15.6&#8221;,
    &#8220;sse.js&#8221;: &#8220;^2.6.0&#8221;,
    &#8220;ssh2-sftp-client&#8221;: &#8220;^11.0.0&#8221;,
    &#8220;underscore&#8221;: &#8220;^1.13.7&#8221;,
    &#8220;uuid&#8221;: &#8220;^11.0.5&#8221;,
    &#8220;webdav&#8221;: &#8220;^5.7.1&#8221;
  },
  &#8220;devDependencies&#8221;: {
...</code></pre><p>35 dependencies, 41 dev dependencies. It&#8217;s <a href="https://github.com/koodo-reader/koodo-reader/blob/master/yarn.lock">yarn.lock</a> file alone is <em>15 thousand lines of code</em>. This is insane.</p><p></p><h2>Execution Speed</h2><p>A common misconception I see often is the idea that</p><blockquote><p>&#8220;if there is a library for it, it must be good&#8221;</p></blockquote><p>As if every library writer were a rockstar programmer who put everything they had into that library.</p><p>In reality, the opposite is true. Most libraries, especially open-source libraries, are written by the average experienced programmer, with no concern for much of anything other than getting features in with the desired abstraction.</p><p>And even in the rare case where the library was written by a great programmer with careful attention to detail and performance, it&#8217;s most likely the case that the library writer had to support a wide range of use cases, which prevents them from making reasonable assumptions about the runtime&#8212;inevitably impacting the library&#8217;s performance and increasing its surface area for bugs.</p><p>The classic example I always use is <code>malloc</code>. When I say I write my own allocators the inevitable reaction I get from most people is: <em>&#8220;do you think you can write a better </em><code>malloc</code><em> than the standard library?&#8221;</em>. The answer is no, but also, I don&#8217;t have to.</p><p>I write narrow purpose allocators that work well for my code base and the problems that a game engine needs to solve, then I write code that is aware of these assumptions. The result is runtime performance many times faster than <code>malloc</code>, while still being flexible enough for what my software needs.</p><div><hr></div><p>Let&#8217;s verify this in practice, again with the clap example. I&#8217;ve re-worked the code to run 10000 command line parsing iterations.</p><p>Here&#8217;s the C version</p><pre><code>#include &lt;stdio.h&gt;
#include &lt;time.h&gt;
#include &#8220;memory.c&#8221;
#include &#8220;cmd_line.c&#8221;

#define ITERATIONS 10000

int main() {
  size_t buffer_size = 64 * 1024;
  u8 *buffer = calloc(1, buffer_size);
  ArenaAllocator arena = arena_from_buffer(buffer, buffer_size);

  char *argv[] = {&#8221;cmdline_example&#8221;, &#8220;build&#8221;, &#8220;--release&#8221;, &#8220;--output&#8221;, &#8220;./bin&#8221;};
  int argc = 5;

  printf(&#8221;Running %d iterations of command line parsing...\n&#8221;, ITERATIONS);

  struct timespec start, end;
  clock_gettime(CLOCK_MONOTONIC, &amp;start);

  for (int i = 0; i &lt; ITERATIONS; i++) {
    arena_reset(&amp;arena);

    CmdLineParser parser = cmdline_create(&amp;arena);

    cmdline_add_command(&amp;parser, &#8220;build&#8221;);
    cmdline_add_flag(&amp;parser, &#8220;debug&#8221;);
    cmdline_add_flag(&amp;parser, &#8220;release&#8221;);
    cmdline_add_option(&amp;parser, &#8220;output&#8221;);

    if (!cmdline_parse(&amp;parser, argc, argv)) {
      printf(&#8221;Parse failed on iteration %d\n&#8221;, i);
      return 1;
    }

    // Mark variables as volatile to prevent optimization
    volatile b32 has_build = cmdline_has_command(&amp;parser, &#8220;build&#8221;);
    volatile b32 has_release = cmdline_has_flag(&amp;parser, &#8220;release&#8221;);
    volatile const char *output = cmdline_get_option(&amp;parser, &#8220;output&#8221;);
  }

  clock_gettime(CLOCK_MONOTONIC, &amp;end);

  long seconds = end.tv_sec - start.tv_sec;
  long nanoseconds = end.tv_nsec - start.tv_nsec;
  double elapsed_ms = seconds * 1000.0 + nanoseconds / 1000000.0;
  double elapsed_us = elapsed_ms * 1000.0;

  printf(&#8221;Total time: %.6f ms\n&#8221;, elapsed_ms);
  printf(&#8221;Average time per iteration: %.3f &#181;s\n&#8221;, elapsed_us / ITERATIONS);

  return 0;
}</code></pre><p>And the Rust version</p><pre><code>use clap::{Parser, Subcommand};
use std::time::Instant;

#[derive(Parser)]
#[command()]
struct Cli {
    #[command(subcommand)]
    command: Option&lt;Commands&gt;,
}

#[derive(Subcommand)]
enum Commands {
    Build {
        #[arg(long)]
        debug: bool,

        #[arg(long)]
        release: bool,

        #[arg(long)]
        output: Option&lt;String&gt;,
    },
}

fn main() {
    let args = vec![&#8221;cmdline_example&#8221;, &#8220;build&#8221;, &#8220;--release&#8221;, &#8220;--output&#8221;, &#8220;./bin&#8221;];

    const ITERATIONS: usize = 10000;

    println!(&#8221;Running {} iterations of command line parsing...&#8221;, ITERATIONS);

    let start = Instant::now();

    for _ in 0..ITERATIONS {
        let cli = Cli::parse_from(&amp;args);

        match &amp;cli.command {
            Some(Commands::Build { debug, release, output }) =&gt; {
                // Force evaluation to prevent optimization
                std::hint::black_box(debug);
                std::hint::black_box(release);
                std::hint::black_box(output);
            }
            None =&gt; {}
        }
    }

    let duration = start.elapsed();

    println!(&#8221;Total time: {:?}&#8221;, duration);
    println!(&#8221;Average time per iteration: {:?}&#8221;, duration / ITERATIONS as u32);
}</code></pre><p>Before I show you the results, what is your guess for how big the speed difference will be?</p><div class="poll-embed" data-attrs="{&quot;id&quot;:393640}" data-component-name="PollToDOM"></div><p>&#8230;</p><p>&#8230;</p><p>&#8230;</p><p>Hey, do not peek!</p><p>&#8230;</p><p>&#8230;</p><p>&#8230;</p><p>Ok, here goes:</p><pre><code>clang -O3 main_cmdline.c -o main &amp;&amp; ./main build --debug --output o.exe
Running 10000 iterations of command line parsing...
Total time: 0.971000 ms
Average time per iteration: 0.100 &#181;s</code></pre><pre><code>cargo run --release -- build --debug --output o.c
    Finished `release` profile [optimized] target(s) in 0.01s
     Running `target/release/cmdline_example build --debug --output o.c`
Running 10000 iterations of command line parsing...
Total time: 52.841334ms
Average time per iteration: 5.284&#181;s</code></pre><p>Turns out the Rust version with <code>clap</code> is **<strong>50x SLOWER**</strong>! 54.41 to be exact<strong>.</strong></p><p>Rust usually runs close to C speeds for equivalent implementations, so the speed difference is likely all overhead from the library.</p><p>50x hit to performance. Just so you can have some magic macros for your command line interface. I guess I&#8217;ll be skipping this one.</p><p></p><h2>Maintainability</h2><p>Finally, maintainability. Another common misconception is that by building on top of libraries, especially libraries that lots of people use, your code will be more stable. After all, these libraries are battle-tested every day, what could go wrong?</p><p>Well for this <a href="https://www.computerenhance.com/">Casey</a> actually has an <a href="https://x.com/cmuratori/status/1426299131270615040">excellent thread</a> outlining how software stability decreases as dependencies increases. The TLDR is: even if dependencies are stable, the more dependencies you have, the higher the changes your software will break. For 100 dependencies you software is basically guaranteed to break in less than 1 year.</p><p>However, I want to bring your attention to something else. Here&#8217;s a question for you to ponder:</p><blockquote><p><em>If the library does break, what is the cost of fixing it?</em></p></blockquote><p>This question is important. When developing software, one must think not just about the cost of writing the software, but the cost of maintaining it for its entire lifetime. That is, the cost of fixing bugs, adding features, supporting new use cases, and so on.</p><p>And one thing that any professional developer knows is that it&#8217;s much easier to work on your own code than on other people&#8217;s code. Even harder still is working on code outside your main project or organization, with a completely different style and different assumptions, i.e library code.</p><p>So even if the library is very stable, it&#8217;s often the case that if there&#8217;s a bug that affects you, it&#8217;s going to take a significant amount of time for you to fix it (or to beg the library writer to fix it). For simple libraries, this time can easily be longer than the time to write the functionality you needed in the first place.</p><p></p><h2>When to use libraries</h2><p>So, I told you at the beginning of this article that I was going to outline the pros and cons of using libraries, and admittedly I focused a lot on the cons. This is by design, my bias is toward not using libraries unless it&#8217;s really necessary.</p><p>Personally, I only consider using a library in two situations:</p><ol><li><p>When the benefits the library provides far outweigh the costs of depending on it, or</p></li><li><p>When there isn&#8217;t enough time to write a proper implementation and I have to make progress (usually due to external pressure)</p></li></ol><p></p><p>Fitting the first situation are usually highly specialized, highly performant, and highly self-contained libraries for which I&#8217;d be hard pressed to implement something better myself. One example is <a href="https://github.com/recp/cglm">cglm</a>, which I use in my engine. Maybe it&#8217;s possible to write a faster and more ergonomic library for 3D math, I just don&#8217;t know how.</p><p>As for the second situation, what I usually do is I try to find the best library available, and then I make a task for myself to eventually replace it&#8217;s implementation. Currently I have two examples in my engine: <a href="https://github.com/floooh/sokol">sokol_gfx</a>, which I use for desktop graphics, and <a href="https://github.com/nicbarker/clay">clay</a>, which I use for UI.</p><p>To be clear, both <code>sokol</code> and <code>clay</code> are extremely well written libraries. Both are low footprint, and highly performant. It would be totally fine to depend on them for the long haul. I just have a preference towards writing code in house.</p><p></p><h2>Conclusion</h2><p>This entire article can be summarized into one sentence:</p><div class="pullquote"><p><em>&#8220;Libraries are not free.&#8221;</em></p></div><p>There are real costs, usually passed down to the user in the form of a bloated, slow application. But also paid developers every day, in the form of dependency management hell, slow iteration times, and obscure bugs that are incredibly hard to fix. All to save what is often times a couple of hours or days of initial investiment. I&#8217;m gonna take door B, Bob.</p><div><hr></div><p></p><p>If you&#8217;d like to be notified of new articles, please consider subscribing.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://posts.cgamedev.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://posts.cgamedev.com/subscribe?"><span>Subscribe now</span></a></p><p></p><p></p>]]></content:encoded></item></channel></rss>