<?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: abathargh</title>
    <description>The latest articles on DEV Community by abathargh (@abathargh).</description>
    <link>https://dev.to/abathargh</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%2F1385197%2F41ed4629-3752-41c8-9553-eda51e6e0b51.png</url>
      <title>DEV Community: abathargh</title>
      <link>https://dev.to/abathargh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abathargh"/>
    <language>en</language>
    <item>
      <title>more nim for embedded software development</title>
      <dc:creator>abathargh</dc:creator>
      <pubDate>Tue, 25 Nov 2025 20:43:24 +0000</pubDate>
      <link>https://dev.to/abathargh/more-nim-for-embedded-software-development-27i</link>
      <guid>https://dev.to/abathargh/more-nim-for-embedded-software-development-27i</guid>
      <description>&lt;p&gt;Writing libraries is fun, but at some point you've got to use them. I've been writing one for roughly two years!&lt;/p&gt;

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

&lt;p&gt;Finally, I moved to writing a not-so-small project using said library (&lt;code&gt;avr_io&lt;/code&gt; - &lt;a href="https://github.com/Abathargh/avr_io" rel="noopener noreferrer"&gt;avr_io@github&lt;/a&gt;), so it is with this newfound knowledge that I bring forth some thoughts about my freshly started nim-application-dev days.&lt;/p&gt;

&lt;p&gt;This is a loose sequel of a previous article, &lt;a href="https://dev.to/abathargh/nim-for-embedded-software-development-33cc"&gt;nim for embedded software development&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note: the following is &lt;em&gt;mainly&lt;/em&gt; about bare-metal firmware for 8-bit microcontrollers, but it can be applied to other domains.&lt;/p&gt;

&lt;h1&gt;
  
  
  arc memory management
&lt;/h1&gt;

&lt;p&gt;I have been experimenting a bit with arc and I like the "don't pay for what you don't use" kind of thing.&lt;/p&gt;

&lt;p&gt;Essentially, if you're not using &lt;code&gt;ref&lt;/code&gt;-types you don't really notice arc, and you can use &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;seq&lt;/code&gt; for relatively low cost in binary size.&lt;/p&gt;

&lt;p&gt;Still haven't experimented too much with size differences to have a precise measurement, but it's not too bad if you don't over-use allocations or some portions of the stdlib.&lt;/p&gt;

&lt;p&gt;If that does become bad, I have the following incantation that sequeezes quite a bit of KB from your binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;switch("gc", "none")
switch("opt", "size")
switch("define", "danger")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also has been suggested to me to use &lt;code&gt;--execptions:quirky&lt;/code&gt;, but in all honesty I don't use exceptions a lot.&lt;/p&gt;

&lt;p&gt;You have to be careful and really know what you're doing tho, with these flags. And some portions of the language may not work, like..&lt;/p&gt;

&lt;h1&gt;
  
  
  object variants
&lt;/h1&gt;

&lt;p&gt;One thing were arc (or a mm ≠ none) may be needed is if you're using object variants.&lt;/p&gt;

&lt;p&gt;I was kind of surprised by this! Aren't they basically just safer tagged &lt;code&gt;union&lt;/code&gt;s from C?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="c"&gt;# An example of an object variant in use&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt;
  &lt;span class="n"&gt;CmdKind&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt;
    &lt;span class="n"&gt;SetBpm&lt;/span&gt;
    &lt;span class="n"&gt;SetValue&lt;/span&gt;
    &lt;span class="n"&gt;SetAmplitude&lt;/span&gt;
    &lt;span class="n"&gt;SetEnvelope&lt;/span&gt;

  &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CmdKind&lt;/span&gt;
    &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;SetBpm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;bpm&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;uint16&lt;/span&gt;
    &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;NoteValue&lt;/span&gt;
    &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;SetAmplitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;amp_chan&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;uint8&lt;/span&gt;
      &lt;span class="n"&gt;amplitude&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint8&lt;/span&gt;
    &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;SetEnvelope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EnvelopeShape&lt;/span&gt;
      &lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The keyword here is &lt;em&gt;safer&lt;/em&gt;; nim achieves this by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forcing you to re-create the object instead of just switching the tag and possibly invalidate the underlying data.&lt;/li&gt;
&lt;li&gt;Raising an exception/panic whenever you access a field that is not tied to the active kind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This second bit is quite nice, because it allows you to catch runtime errors with custom panicoverride handles; for example, I just set up a blinking LED for this kind of stuff, so I have a visual cue that something went wrong.&lt;/p&gt;

&lt;p&gt;On the other side, the message passed to the panic handle is built with &lt;code&gt;appendString&lt;/code&gt;, which implies at least using &lt;code&gt;-mm:arc --define:useMalloc&lt;/code&gt;, so if you want to use object variants AND be safe about them, you cannot go with just &lt;code&gt;--mm:none&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I got three issues with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It would be nice to maybe have a compiler flag that enforces compile-time checking that you are accessing variants through &lt;code&gt;case..of&lt;/code&gt; blocks, so to catch these accesses when building. You can actually do this with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ProveField:on"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"warningAsError"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ProveField:on"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it's quite picky and it seems like it implies arc, as it requires &lt;code&gt;newObj&lt;/code&gt;- to be defined.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It also would be nice to be able to override the invalid access message creation mechanism, to avoid calling &lt;code&gt;appendString&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Currently (as I'm writing this post nim v2.2.6 just got released), panicoverride does not support the full extent of nim features, so doing anything more than blinking a LED is a bit cumbersome (I am working to try and put this into upstream).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anyways, if you want to use object variants, and you are very sure you're great at not writing bad code, you can disable the checks (and the need for arc) with &lt;code&gt;--fieldChecks:off&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Spoiler: I had at least 3 crashes that were caught by these safety features. Even if you are good, everyone does a bit of copy pasting, and mistakes can happen.&lt;/p&gt;

&lt;h1&gt;
  
  
  trying not to allocate
&lt;/h1&gt;

&lt;p&gt;So, the age-old problem with embedded about not wanting to do dynamic allocations.&lt;/p&gt;

&lt;p&gt;I got two nice approaches here:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;var array&lt;/code&gt;s
&lt;/h2&gt;

&lt;p&gt;Passing a var array (or a wrapper to it) in nim is quite nice, since you have generics, can enforce """&lt;em&gt;ref-like&lt;/em&gt;""" semantics for value types (using &lt;code&gt;{.byref.}&lt;/code&gt; to enforce passing by pointer), and arrays do not decade to pointers, unlike in C. Also, I believe var parameters are always passed by pointer in the generated C code.&lt;/p&gt;

&lt;p&gt;So you can just use this approach with stack-allocated or global buffers.&lt;/p&gt;

&lt;h2&gt;
  
  
  non owning views into arrays
&lt;/h2&gt;

&lt;p&gt;Now I had this headache for a day or two, about why I was getting sequences being generated and allocated in my sequence-less code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;chan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scd_chan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ChannelMode&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scd_chan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;incl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;channel_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_amplitude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;arpeggio_bufs&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scd_chan&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_arpeggio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;reps&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;or_else&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out that slicing an array and passing said slice through an &lt;code&gt;openArray&lt;/code&gt; input parameter is not free in nim.&lt;/p&gt;

&lt;p&gt;The way around it is using &lt;a href="https://nim-lang.org/docs/system.html#toOpenArray%2Cseq%5BT%5D%2Cint%2Cint" rel="noopener noreferrer"&gt;toOpenArray&lt;/a&gt; to generate a non-owning view through the array.&lt;/p&gt;

&lt;h1&gt;
  
  
  compile time tables
&lt;/h1&gt;

&lt;p&gt;This is one of the small things that I love about nim, that almost anything you can use at runtime, you can also use at compile time.&lt;/p&gt;

&lt;p&gt;Lots of times, to avoid many allocations or to pre-compute stuff, you want to create arrays or tables with metadata and such.&lt;/p&gt;

&lt;p&gt;One pattern I learnt to use and love is the anonymus proc generating comptime arrays (notice that if the user adds or removes an enum entry from &lt;code&gt;ErrorCode&lt;/code&gt;, this does not require refactoring):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt;
  &lt;span class="n"&gt;ErrorStrings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ord&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="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;symbolName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ErrorCode&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&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;Clear, succint, effective.&lt;/p&gt;

&lt;h1&gt;
  
  
  Metaprogramming
&lt;/h1&gt;

&lt;p&gt;The current project I am working on is made of 3 subprojects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An embedded driver&lt;/li&gt;
&lt;li&gt;An embedded application&lt;/li&gt;
&lt;li&gt;A desktop cli tool to interact with the ones above&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before that, I have worked for ~2 years on avr_io, which is mainly a series of wrappers, and easy to use set of API to interact with AVR microcontrollers.&lt;/p&gt;

&lt;p&gt;There, I used a lot of macros and templates to perform AST manipulation to e.g. generate ISR handlers easily, and to try to provide 0-overhead abstractions.&lt;/p&gt;

&lt;p&gt;Here in these projects?&lt;/p&gt;

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

&lt;p&gt;Macros are incredible in nim, but they are hard to maintain and best kept in libraries. Nim is so expressive that you will rarely need them in application code anyways.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building
&lt;/h1&gt;

&lt;p&gt;As I said, my current project has 3 projects in 1, with one of these being a CLI app, which means I have different config.nims and targets and such.&lt;/p&gt;

&lt;h2&gt;
  
  
  nimble, atlas and make
&lt;/h2&gt;

&lt;p&gt;I found nimble to be very cumbersome to use in these scenarios, as config.nims and nims file in general do not seem to work properly with nested nimble projects and custom tasks.&lt;/p&gt;

&lt;p&gt;So I very sadly went back to good old &lt;code&gt;make&lt;/code&gt; and a single nimble file, which works well enough for me (since I mainly work on linux/macosx). I have a single nimble file in my root directory, and different targets in the Makefile.&lt;/p&gt;

&lt;p&gt;Also, I started using atlas a bit and it was quite a positive experience.&lt;/p&gt;

&lt;p&gt;Atlas is nim's brand new "package cloner". I would describe it as a really nice way to vendor dependencies and nim compiler versions, it is sort of like if &lt;code&gt;go mod vendor&lt;/code&gt; from go, and &lt;code&gt;virtualenv&lt;/code&gt; from python had a child.&lt;/p&gt;

&lt;p&gt;Not only that, but atlas allow you to link multiple projects together to unlock local-first workspaces. I am experimenting with it and liking it quite a bit. It works much better than nimble for my personal opinion and ergonomical preferences.&lt;/p&gt;

</description>
      <category>nim</category>
      <category>embedded</category>
      <category>iot</category>
      <category>language</category>
    </item>
    <item>
      <title>nim, LLMs and me: finding a balance between pragmatism and the joy of programming</title>
      <dc:creator>abathargh</dc:creator>
      <pubDate>Mon, 13 Oct 2025 06:49:17 +0000</pubDate>
      <link>https://dev.to/abathargh/nim-llms-and-me-finding-a-balance-between-pragmatism-and-the-joy-of-programming-3pbg</link>
      <guid>https://dev.to/abathargh/nim-llms-and-me-finding-a-balance-between-pragmatism-and-the-joy-of-programming-3pbg</guid>
      <description>&lt;p&gt;I recently got one of the new MacBook Air laptops, with the M4 ARM CPU, mainly for music production.&lt;/p&gt;

&lt;p&gt;Once I had my hands on it though, I could not resist and I started installing a bit of my usual programming environment on it; one thing led to another, and I found myself enjoying the whole setup quite a bit.&lt;/p&gt;

&lt;p&gt;So as usual when finding the right ergonomics, passion gets channeled through the ease of use of the tools you have in your hands, and creativity flows.&lt;/p&gt;

&lt;p&gt;I had been working on and off for some months on the tools I use to program avr chips in nim, and I was hoping to add some code to discover serial devices automatically when programming arduino boards.&lt;/p&gt;

&lt;p&gt;Nothing I found online was quite where I wanted, as I wished for something akin to &lt;code&gt;pyserial&lt;/code&gt; &lt;code&gt;list_ports.comports&lt;/code&gt;, which just tells you - in the usual simple and to the point python fashion - what are the serial devices connected to your computer.&lt;/p&gt;

&lt;p&gt;So I wrote my own:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;enumerate_serial_devices&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;walkDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/dev/"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pc_file&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extract_filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tty"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c"&gt;# this extracts the vid/pid from /sys/class/tty/.../device/uevent&lt;/span&gt;
&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;get_vid_pid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;vid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dev_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="p"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tty_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;fmt"/sys/class/tty/{dev_name}/device"&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;evt_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;fmt"/sys/class/tty/{dev_name}/device/uevent"&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dir_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tty_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evt_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;evt_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;"PRODUCT="&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PRODUCT="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="p"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_hex_int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_hex_nt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0'u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0'u16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can find the complete code &lt;a href="https://github.com/Abathargh/avrman/" rel="noopener noreferrer"&gt;@github.com/Abathargh/avrman&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything was fine, as usual nim is very expressive and manages to embody python's simplicity.&lt;/p&gt;

&lt;p&gt;But now to the issue: &lt;code&gt;/sys&lt;/code&gt; is a linux feature, and other systems (even UNIX-like ones, like MacOSX) do not provide it. Now, I thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How difficult could it be to do the same for Mac?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Turns out that it is not maybe hard, but much less straightforward and immediate.&lt;/p&gt;

&lt;p&gt;I studied the issue for a bit, but the combination of this being a "side-problem" and the fact that no one was paying me to do something not fun, led me to something I had not done really seriously up until now: using one of the LLMs to completely generate the code for me.&lt;/p&gt;

&lt;p&gt;Now I've been using these tools for a while, like most of us, and I mainly relegated them to a sort of glorified "&lt;strong&gt;google when it still was good, but on steroids&lt;/strong&gt;", but now I wanted to have full code generation, and boy was I surprised.&lt;/p&gt;

&lt;p&gt;I fed this problem into Claude (my go to one, I just find it generates better code for my taste and standards, with respect to its competitors), and I was really surprised by the fact that the code actually worked (with minor tweaks) for such a niche use case and programming language, on a specific platform.&lt;/p&gt;

&lt;p&gt;These tools have been getting quite better even at less known languages, and I have been surprised recently, because they are just starting to get good for me.&lt;/p&gt;

&lt;p&gt;Now, to the real issue at heart.. I love programming, I really do, it's not only a job for me, but some kind of artisanal thing I do with some of my time on this beautiful planet, so let me philosophize and maybe romanticize a bit: I am afraid that we may lose this kind of feeling that the joy of programming gives us by only feeding prompts to a lifeless program.&lt;/p&gt;

&lt;p&gt;Not only that, but I fear that learning to program right now will have the double-edged sword that I observe on myself after this experience: I now have a working driver for enumerating serial devices on MacOSX and I cannot explain to you how it works, because I did not think it out myself. I know I can learn it, but why would I?&lt;/p&gt;

&lt;p&gt;I have been a kid, a student, and a learner of (sometimes) boring things, so I know that people will take shortcuts for this kind of stuff, and not look back at how it actually is done. How do we solve this issue? I think the biggest problem of the coming years in this landscape will be an educational one.&lt;/p&gt;

&lt;p&gt;I have no answer for now, but I for sure have hope.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>genai</category>
      <category>llm</category>
      <category>nim</category>
    </item>
    <item>
      <title>optimizing c structs layouts</title>
      <dc:creator>abathargh</dc:creator>
      <pubDate>Sat, 07 Dec 2024 14:25:38 +0000</pubDate>
      <link>https://dev.to/abathargh/optimizing-c-structs-layouts-4kkm</link>
      <guid>https://dev.to/abathargh/optimizing-c-structs-layouts-4kkm</guid>
      <description>&lt;p&gt;Let's consider a simple c struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&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;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;len&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;Suppose that this code is being run as a part of a program executing on a 64-bit machine: what would you expect the result of &lt;code&gt;sizeof(struct foo)&lt;/code&gt; to be? &lt;/p&gt;

&lt;p&gt;Most people that never had to mess with struct sizes and optimizations would guess that it should be 17...&lt;/p&gt;

&lt;p&gt;... but &lt;em&gt;it's 24&lt;/em&gt;! Why is that?&lt;/p&gt;

&lt;p&gt;The reason for this behavior is that compilers optimize struct layouts for speed, and it's the modern norm that aligned memory accesses are the fastest way to access data.&lt;/p&gt;

&lt;p&gt;This means that, depending on the type of field and cpu, your data will have some alignment and will be positioned such that that alignment is respected (or, such that &lt;code&gt;field-address % field-alignment == 0&lt;/code&gt;). &lt;/p&gt;

&lt;h2&gt;
  
  
  size, alignment, padding
&lt;/h2&gt;

&lt;p&gt;In the case of the previous example, pointers and 64-bit fields are 8B aligned on 64-bit machines, and this means that, in order to force a layout where everything in the struct is aligned, the compiler will generate some padding between the &lt;code&gt;flag&lt;/code&gt; and &lt;code&gt;len&lt;/code&gt; fields:&lt;/p&gt;

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

&lt;p&gt;Now let's consider another example, where a struct like this is defined, on the same machine as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&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;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;short&lt;/span&gt; &lt;span class="n"&gt;s1&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;i1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;short&lt;/span&gt; &lt;span class="n"&gt;s2&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;i2&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;How do we go about computing its size?&lt;/p&gt;

&lt;p&gt;There are three rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Struct fields want to be aligned with their own natural alignment.&lt;/li&gt;
&lt;li&gt;The overall struct alignment is equal to the alignment of its widest field&lt;/li&gt;
&lt;li&gt;If you had to put two structs of the same type side by side, the second one should be aligned to its alignment -- this means that structs must have trailing padding up to their alignment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quick recap on basic types alignment and size for 64-bit machines:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;th&gt;size&lt;/th&gt;
&lt;th&gt;alignment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;char&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;short&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;long&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;float&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;double&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pointers&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Also remember that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arrays have the alignment of their value type, and size that is &lt;code&gt;sizeof(type) * elements number&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Unions have the alignment and size of their widest member.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And you can use the super useful &lt;code&gt;sizeof&lt;/code&gt; and &lt;code&gt;_Alignof&lt;/code&gt; operators to get this information for your custom types. Note that &lt;code&gt;_Alignof&lt;/code&gt; is available from C11 onward, and is called &lt;code&gt;alignof&lt;/code&gt; starting with C23. It was always &lt;code&gt;alignof&lt;/code&gt; from what I understand in C++, since C++11.&lt;/p&gt;

&lt;p&gt;For more information, the bible on this topic is &lt;a href="http://www.catb.org/esr/structure-packing/" rel="noopener noreferrer"&gt;The Lost Art of Structure Packing&lt;/a&gt;, from which I learned almost everything I know about this, together with a lot of practice and hands-on experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  optimizing your structs: stropt
&lt;/h2&gt;

&lt;p&gt;This topic here is something that comes up rather frequently at work, where saving bytes here and there is super important when sending huge loads of data continuously in queues and whatnot.&lt;/p&gt;

&lt;p&gt;In order to make my life easier, I wrote a tool that produces some statistics on a type you pass as input, with reference to a source file or code snippet, it's called &lt;strong&gt;&lt;em&gt;stropt&lt;/em&gt;&lt;/strong&gt; (struct optimizer).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Abathargh/stropt" rel="noopener noreferrer"&gt;Abathargh/stropt on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  build &amp;amp; install
&lt;/h3&gt;

&lt;p&gt;If you have a local go installation you can go right ahead and build or install the application directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Abathargh/stropt
go build

// or, &lt;span class="k"&gt;if &lt;/span&gt;you want to &lt;span class="nb"&gt;install &lt;/span&gt;this directly
go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/Abathargh/stropt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Already compiled binaries for a list of os/archs combinations are also provided in the github release page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Abathargh/stropt/releases" rel="noopener noreferrer"&gt;stropt binaries&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  using the tool
&lt;/h3&gt;

&lt;p&gt;You can either use stropt by passing the source to analyze as a string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;stropt &lt;span class="s2"&gt;"struct meta"&lt;/span&gt; &lt;span class="s2"&gt;"struct meta { int a; double d; float f[100];};"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Or you can pass a file in which the definition is contained:&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="c1"&gt;// test.c&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&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;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;iptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;stropt &lt;span class="nt"&gt;-file&lt;/span&gt; test.c &lt;span class="s2"&gt;"struct test"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The tool can also provide a possible optimization for your types by using the &lt;code&gt;-optimize&lt;/code&gt; flag, and it's aware of fields that are structs themselves:&lt;/p&gt;

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

&lt;p&gt;Note that the &lt;code&gt;verbose&lt;/code&gt; flag is used to show inner structs (and unions) along with their fields alignment and size.&lt;/p&gt;

&lt;h2&gt;
  
  
  what's next
&lt;/h2&gt;

&lt;p&gt;This tool was written in go using the great &lt;code&gt;modernc.org/cc&lt;/code&gt; C compiler front-end for parsing C code, and &lt;code&gt;lipgloss&lt;/code&gt; from charmbracelet for the UI.&lt;/p&gt;

&lt;p&gt;I'm writing this for myself but I'm happy to share it publicly; I'd like to make this a webapp for easier use directly in a browser, so probably that's the next thing I'm going to be working on!&lt;/p&gt;

</description>
      <category>c</category>
      <category>cpp</category>
      <category>go</category>
      <category>architecture</category>
    </item>
    <item>
      <title>harlock v0.5.1 released</title>
      <dc:creator>abathargh</dc:creator>
      <pubDate>Sat, 13 Jul 2024 13:24:30 +0000</pubDate>
      <link>https://dev.to/abathargh/harlock-v051-released-15l3</link>
      <guid>https://dev.to/abathargh/harlock-v051-released-15l3</guid>
      <description>&lt;p&gt;It is with immense pleasure that I announce that version 0.5.1 off the harlock scripting language is out!&lt;/p&gt;

&lt;p&gt;Here is the detailed release log, with a list the artifacts to install the language on debian-like systems, or directly a binary for the supported architectures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Abathargh/harlock/releases/tag/v0.5.1" rel="noopener noreferrer"&gt;Release note + artifacts @github/Abathargh/harlock&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build from source
&lt;/h2&gt;

&lt;p&gt;Notice that you can always compile and install harlock by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/Abathargh/harlock/cmd/harlock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Abathargh/harlock
make &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Release details
&lt;/h2&gt;

&lt;p&gt;This v0.5.1 release is a bugfix one, that solidifies harlock usage within build pipelines.&lt;/p&gt;

&lt;p&gt;The main issues that were tackled are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correctly handling runtime and evaluation errors being raised at the top-level scope to trigger a non-zero error code. This led to silent errors being passed inside of pipelines using harlock.&lt;/li&gt;
&lt;li&gt;Drop support for go 1.15+ unsupported targets.&lt;/li&gt;
&lt;li&gt;Adding previously missing .exe suffix for windows executable names when cross-compiling for windows on non-windows&lt;/li&gt;
&lt;li&gt;Minor fixes to .gitignore and Makefile.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last couple of releases included a new error system which was thoroughly tested and fixing it is the main reason for v0.5.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage and new developments
&lt;/h2&gt;

&lt;p&gt;I've been using harlock a lot to test the avr_io nim library that I work on, alongside personal projects where I need firmware to be updated over the wire/air with huge success.&lt;/p&gt;

&lt;p&gt;A nice working project using the language can be found in the bootloader example for avr_io, where it is used to showcase the library capabilities when writing bootloaders for embedded applications.&lt;/p&gt;

&lt;p&gt;I wrote an in-depth article on how to use harlock for these kind of scenarios on antima at the &lt;a href="https://antima.it/en/harlock-a-small-language-to-handle-hex-and-elf-files/" rel="noopener noreferrer"&gt;following link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>embedded</category>
      <category>opensource</category>
      <category>devops</category>
    </item>
    <item>
      <title>nim for embedded software development</title>
      <dc:creator>abathargh</dc:creator>
      <pubDate>Thu, 28 Mar 2024 07:29:20 +0000</pubDate>
      <link>https://dev.to/abathargh/nim-for-embedded-software-development-33cc</link>
      <guid>https://dev.to/abathargh/nim-for-embedded-software-development-33cc</guid>
      <description>&lt;p&gt;While we in embedded-land are mostly working with either C or C++ on our professional ventures, often with proprietary tooling and whatnot, I always find some much appreciated respite in tinkering with other alternatives when wasting time on hobbies and side-projects.&lt;/p&gt;

&lt;p&gt;In the last year or so, I delved into exploring other venues to solve my embedded headaches and landed onto the &lt;code&gt;nim programming language&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  nim compiles to c (and c++, objective-c, js)
&lt;/h3&gt;

&lt;p&gt;This means that any target with an existing c compiler is automatically supported by nim.&lt;/p&gt;

&lt;p&gt;Not only that, but calling c code (and c++, objective-c, etc.) is really simple to do and, from what I see, 0-overhead.&lt;/p&gt;

&lt;p&gt;You can also easily check the generated C sources, which are human readable, even if with a lot of noise. This can be achieved by specifying a &lt;code&gt;--nimcache&lt;/code&gt; directory when compiling.&lt;/p&gt;

&lt;h3&gt;
  
  
  writing, building, shipping
&lt;/h3&gt;

&lt;p&gt;Like all modern stuff, we have a sane module system (bye bye text-based &lt;code&gt;#include&lt;/code&gt;s), an ergonomic compiler and a nice, basic package manager.&lt;/p&gt;

&lt;p&gt;The compiler lets you use a script-like subset of the language as a format for configuration files. These may contain compiler switches and system-specific flags. It integrates seamlessly with the &lt;code&gt;nimble&lt;/code&gt; package manager, which lets you write tasks that can be executed both after building or as sorts of standalone targets.&lt;/p&gt;

&lt;h3&gt;
  
  
  writing a simple hello world for AVR is trivial (ish)
&lt;/h3&gt;

&lt;p&gt;This is a valid program that can be run on a x64 intel CPU and, without any changes, on an 8-bit atmega microcontroller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;discard&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To compile on AVR, you just have to provide some more configuration on how to handle critical errors without the os covering our backs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="c"&gt;# panicoverride.nim&lt;/span&gt;

&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;importc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;stdlib.h&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cdecl&lt;/span&gt;&lt;span class="p"&gt;.}&lt;/span&gt;

&lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;stack_trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;off&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;profiler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;off&lt;/span&gt;&lt;span class="p"&gt;.}&lt;/span&gt;

&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;rawoutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;discard&lt;/span&gt;

&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;rawoutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;discard&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;pop&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 couple of compiler flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="c"&gt;# config.nims&lt;/span&gt;

&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"standalone"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cpu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"avr"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stackTrace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"off"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"lineTrace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"off"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"passC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-mmcu=atmega328p"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"passL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-mmcu=atmega328p"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nimcache"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".nimcache"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avr.standalone.gcc.options.linker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-static"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avr.standalone.gcc.exe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"avr-gcc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"avr.standalone.gcc.linkerexe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"avr-gcc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="n"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gcc.options.always"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-w -fmax-errors=3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that these is where you specify which c compiler to use, to then actually generate the final binaries.&lt;/p&gt;

&lt;p&gt;The compiler is identified by the &lt;code&gt;cpu.os.compiler&lt;/code&gt; name (&lt;code&gt;avr.standalone.gcc&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The compiler executable is specified through the &lt;code&gt;exe&lt;/code&gt; property.&lt;/li&gt;
&lt;li&gt;The linker executable is specified through the &lt;code&gt;linkerexe&lt;/code&gt; property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dump these code snippets into the following files:&lt;/p&gt;

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

&lt;p&gt;Run the compiler...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nim c avr_hw.nim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;...and check its output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;avr_hw:     file format elf32-avr


Disassembly of section .text:

00000000 &amp;lt;.text&amp;gt;:
   0:   0c 94 38 00     jmp 0x70
   4:   0c 94 4a 00     jmp 0x94
   8:   0c 94 4a 00     jmp 0x94
  ...
  70:   11 24           eor r1, r1
  72:   1f be           out 0x3f, r1
  74:   cf ef           ldi r28, 0xFF
  76:   d0 e1           ldi r29, 0x10
  78:   de bf           out 0x3e, r29
  7a:   cd bf           out 0x3d, r28
  7c:   21 e0           ldi r18, 0x01
  7e:   a0 e0           ldi r26, 0x00
  80:   b1 e0           ldi r27, 0x01
  82:   01 c0           rjmp    .+2 
  84:   1d 92           st  X+, r1
  86:   ae 30           cpi r26, 0x0E
  88:   b2 07           cpc r27, r18
  8a:   e1 f7           brne    .-8
  8c:   0e 94 52 00     call    0xa4
  90:   0c 94 53 00     jmp 0xa6
  94:   0c 94 00 00     jmp 0   
  98:   ff cf           rjmp    .-2     
  9a:   08 95           ret
  9c:   08 95           ret
  9e:   ff cf           rjmp    .-2
  a0:   ff cf           rjmp    .-2
  a2:   ff cf           rjmp    .-2
  a4:   ff cf           rjmp    .-2
  a6:   f8 94           cli
  a8:   ff cf           rjmp    .-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Worked like a charm!&lt;/p&gt;

&lt;h3&gt;
  
  
  foreign function interface
&lt;/h3&gt;

&lt;p&gt;Want to use &lt;code&gt;_delay_ms&lt;/code&gt; from &lt;code&gt;util/delay.h&lt;/code&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;delay_ms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;us&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;importc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"_delay_ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"util/delay.h"&lt;/span&gt;&lt;span class="p"&gt;.}&lt;/span&gt;

&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;delay_ms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As shown, it's really easy to integrate existing c code in your programs, you don't have to rewrite everything in nim. Note that there are tools to also translate c code to nim (c2nim, futhark).&lt;/p&gt;

&lt;h3&gt;
  
  
  metaprogramming
&lt;/h3&gt;

&lt;p&gt;Metaprogramming is nim killer-feature in my opinion.&lt;/p&gt;

&lt;p&gt;nim has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile-time functions, which get executed in a VM embedded within the compiler, and supports a subset of the language to be evaluated at compile time.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;staticRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my_file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# the file gets read at compile time!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Generics and concepts, which from what I observed, are completely 0 cost at runtime, and are really only present in nim code, not in the c-generated one. Using them in combination with typeclasses enables quite powerful patterns.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MappedIoRegister&lt;/span&gt;&lt;span class="o"&gt;*[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;uint16&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;distinct&lt;/span&gt; &lt;span class="n"&gt;uint16&lt;/span&gt; &lt;span class="sd"&gt;## \&lt;/span&gt;
  &lt;span class="sd"&gt;## A register that can either contain a byte-sized or word-sized datum.&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="n"&gt;ioPtr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MappedIoRegister&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;ptr&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="k"&gt;ptr&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Templates, which are hygienic (with scoped symbols) c macros, essentially a replace-mechanism that allows you to have "true inlining". Combining this with operator overloading is really nice.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;volatile&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="o"&gt;*[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MappedIoRegister&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;volatile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;volatileLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioPtr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="o"&gt;[]=&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="o"&gt;*[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MappedIoRegister&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;volatile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;volatileStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioPtr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Macros, which are special functions taking in Abstract Syntax Tree (AST) representations of nim code and spewing out ASTs that are transformations of its inputs. This allows for some pretty crazy stuff.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;&lt;span class="c"&gt;# VectorInterrupt enum definition omitted..&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="n"&gt;vectorDecl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$1&lt;/span&gt;&lt;span class="s"&gt;  __vector_"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; 
  &lt;span class="s"&gt;"""
    &lt;/span&gt;&lt;span class="si"&gt;$3&lt;/span&gt;&lt;span class="s"&gt; __attribute__((__signal__,__used__,__externally_visible__)); 
    &lt;/span&gt;&lt;span class="si"&gt;$1&lt;/span&gt;&lt;span class="s"&gt; __vector_"""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$3&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="n"&gt;isr&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;VectorInterrupt&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;untyped&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;untyped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="sd"&gt;## Turns the passed procedure `p` into an interrupt &lt;/span&gt;
  &lt;span class="sd"&gt;## service routine.&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pnode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;nnkStmtList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;pnode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;expectKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nnkProcDef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;addPragma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newIdentNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exportc"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;addPragma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pnode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;newNimNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nnkExprColonExpr&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;newIdentNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"codegenDecl"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
      &lt;span class="n"&gt;newLit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectorDecl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;pnode&lt;/span&gt;

&lt;span class="c"&gt;# Now we can map functions to an interrupt&lt;/span&gt;

&lt;span class="k"&gt;proc &lt;/span&gt;&lt;span class="nf"&gt;timer0_compa_isr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;isr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Timer0CompAVect&lt;/span&gt;&lt;span class="p"&gt;).}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="c"&gt;# do stuff when the timer0 compare A interrupt gets triggered&lt;/span&gt;
  &lt;span class="k"&gt;discard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All code snippets are taken from the &lt;a href="https://github.com/Abathargh/avr_io" rel="noopener noreferrer"&gt;avr_io&lt;/a&gt; library, a small project that I maintain.&lt;/p&gt;

&lt;p&gt;Note that we can use &lt;code&gt;exportc&lt;/code&gt; to generate code that will interact with c, and &lt;code&gt;codegenDecl&lt;/code&gt; to manipulate the c-generated code: this is incredibly powerful, especially for writing libraries.&lt;/p&gt;

&lt;p&gt;As a rule of thumb, use these features in this order and go to the next one only if needed: &lt;code&gt;non-meta stuff -&amp;gt; generics -&amp;gt; templates -&amp;gt; macros&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  memory management
&lt;/h3&gt;

&lt;p&gt;Memory management is highly configurable in nim.&lt;/p&gt;

&lt;p&gt;Starting from v2 onward, the memory management policy used by default is based on a reference counting approach, that also handles cycles (&lt;code&gt;-mm:orc&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;You can also choose to use a more easy-to-reason strategy, which also uses reference counting but without support for cycles (&lt;code&gt;-mm:arc&lt;/code&gt;). Notice that both are deterministic and not stop-the-world.&lt;/p&gt;

&lt;p&gt;By experimenting, I noticed that binary size can become a bit larger with orc/arc, so if it is really a problem, you can always opt in not managing your memory at all (&lt;code&gt;-mm:none&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Why does that matter? Because nim has managed types, but I did not experiment with them enough to have formed an opinion on how good or not they are in bare-metal situations!&lt;/p&gt;

</description>
      <category>nim</category>
      <category>embedded</category>
      <category>metaprogramming</category>
      <category>arduino</category>
    </item>
  </channel>
</rss>
