<?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: TaiKedz</title>
    <description>The latest articles on DEV Community by TaiKedz (@taikedz).</description>
    <link>https://dev.to/taikedz</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%2F12252%2F2dcdd5b9-d537-494e-b795-0488359d7dc6.png</url>
      <title>DEV Community: TaiKedz</title>
      <link>https://dev.to/taikedz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/taikedz"/>
    <language>en</language>
    <item>
      <title>I am so done here. The slop is overwhelming.</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Mon, 02 Feb 2026 12:15:46 +0000</pubDate>
      <link>https://dev.to/taikedz/i-am-so-done-here-the-slop-is-overwhelming-43gm</link>
      <guid>https://dev.to/taikedz/i-am-so-done-here-the-slop-is-overwhelming-43gm</guid>
      <description>&lt;p&gt;I started on dev.to because it seemed like a good place to engage with a tech community that didn't feel gamified and ad-ridden.&lt;/p&gt;

&lt;p&gt;Then so many flood accounts posting patently incorrect ill-applied CompSci 101 concepts started appearing. Then the scam accounts. And the short posts designed to funnel to Medium and other sites for monetization. &lt;/p&gt;

&lt;p&gt;And of course now nearly every sponsored event is some AI slopfest challenge.&lt;/p&gt;

&lt;p&gt;I started computing because I like building stuff and solving problems. Things that would remain, skills of my own I could take forward.&lt;/p&gt;

&lt;p&gt;AI has this tendency, both in programming and in art/writing to promise this: you can get the aesthetic for free, so long as you don't care about the craft. You don't need to get it, just continue paying a subscription, don't sweat the rest.&lt;/p&gt;

&lt;p&gt;It's the microwave freezer meals of our domain; where some of us came to cook, the industry just wants us to consume and dispose of. People using it at home is bad enough, and that'stheir choice; but then restaurants start doing it - and suddenly even the professionals aren't even cooking.&lt;/p&gt;

&lt;p&gt;I had a chat recently with an AI programming enthusiast, their take was that software made predominantly with AI didn't so much need maintaining, just regenerate new software. Imagine that! Disposable software! Draining how much freshwater, burning how much fuel, every time you need tk regenerate a website for a customer?&lt;/p&gt;

&lt;p&gt;What the actual duck.&lt;/p&gt;

&lt;p&gt;I am done here, Dev.to . It was a nice idea. I'm sure the community will grow, and I'll be a dinosaur fossil, and all that.&lt;/p&gt;

&lt;p&gt;I'm just so sorry it happened.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>slop</category>
    </item>
    <item>
      <title>Shell/Python vs Go - practical thoughts form a reimplementation project</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Mon, 09 Jun 2025 13:39:50 +0000</pubDate>
      <link>https://dev.to/taikedz/shell-scripting-vs-go-practical-notes-form-a-reimplementation-project-1b18</link>
      <guid>https://dev.to/taikedz/shell-scripting-vs-go-practical-notes-form-a-reimplementation-project-1b18</guid>
      <description>&lt;p&gt;This is perhaps not your typical "Golang vs (language)" post... I've seen it said in various places (citations lost, please roll with it) that Go is a good replacement for shell scripting. At first, I was highly skeptical - Go is a compliled, stricly typed language with more boilerplate to "Hello world" than needed in any scirpting language. But as a compiled language, it does make sense for portability, and as a properly and strictly typed language, it makes performing complex operations easier to implement... so it was worth trying out.&lt;/p&gt;

&lt;p&gt;TL/DR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go is a credible alternative to python and shell, for me&lt;/li&gt;
&lt;li&gt;I did &lt;a href="https://github.com/taikedz/alpacka-ng" rel="noopener noreferrer"&gt;Alpacka/NG&lt;/a&gt; as an experiment to convert form shell to Go&lt;/li&gt;
&lt;li&gt;Publishing Go modules for sharing code is super easy&lt;/li&gt;
&lt;li&gt;Establishing supply chain trust is an issue&lt;/li&gt;
&lt;li&gt;Shell and Python still definitely have their places&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Alpacka, as a bash script
&lt;/h2&gt;

&lt;p&gt;Several years ago when I was still a bright-eyed and bushy-tailed distro-hopper, I kept on running into the same problem: "&lt;em&gt;which package manager command and keyword combination do I need on this distro again??&lt;/em&gt;" I wrote a simple script I called Alpacka and whose command I rendered as &lt;code&gt;paf&lt;/code&gt; (naming choice lost to history at this point) to help me. It supported a variety of package managers, and is still available &lt;a href="https://gitlab.com/taikedz/alpacka" rel="noopener noreferrer"&gt;on gitlab as Alpacka&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It had however three notable drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It depended on the local commands, which varied in flavour and version over distro and distro versions, of which bash&lt;/li&gt;
&lt;li&gt;Bash's syntax is not oriented to complex data structure manipulation&lt;/li&gt;
&lt;li&gt;Predictable modularisation of source code is hard without workarounds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The version issue was multi-fold: not only was it a sequential version problem (1.0, 1.1, 2.0, etc) but also an implementation problem (BSD variant, GNU variant, Busybox variant) for which outputs and flags would often vary in key places. Depending on given behaviours and outputs of these would be tricky sometimes, and limit the available operations to the common base denominator. At the time for example, I think Busybox did not fully implement Perl Compatible Regular Expressions (PCRE) in its &lt;code&gt;grep&lt;/code&gt; implementation (or was it &lt;code&gt;sed&lt;/code&gt;?) so implementing certain actions was difficult, if not downright impossible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shell scripting limitations
&lt;/h3&gt;

&lt;p&gt;The lack of rich types like maps, and the inability to &lt;code&gt;return&lt;/code&gt; arrays (need to pass around in global variables, yuck, pollutes variables space), prevented things like function recursion (possible, with hoops, caveats, boilerplate and metaprogramming) and key-value lookup (perhaps possible, but too tedious to warrant implementing). For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;greetings&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;name &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hail &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt; &lt;span class="c"&gt;# no return - just echo to stdout&lt;/span&gt;
    &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# use `()` notation to force an array, split on whitespace&lt;/span&gt;
&lt;span class="nv"&gt;phrases&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;greetings Alex Jay Sam&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Access an array using `"${varname[@]}"`&lt;/span&gt;
&lt;span class="c"&gt;# quotes and extra chars mandatory - else various alternative effects may happen&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;phrase &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;phrases&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"We say, &lt;/span&gt;&lt;span class="nv"&gt;$phrase&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Problem - prints:&lt;/span&gt;
&lt;span class="c"&gt;# We say, Hail&lt;/span&gt;
&lt;span class="c"&gt;# We say, Alex!&lt;/span&gt;
&lt;span class="c"&gt;# We say, Hail&lt;/span&gt;
&lt;span class="c"&gt;# We say, Jay!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get away from the effect of the automatic splitting on whitespace, we must use a global variable array&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;greetings&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# also, make `name` non-global (all vars are global by default)&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;name

  &lt;span class="c"&gt;# Set a global variable for the caller to access afterwards&lt;/span&gt;
  &lt;span class="nv"&gt;PHRASES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;:&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# old bash compatibility&lt;/span&gt;
  &lt;span class="c"&gt;# arrays cannot be empty, so this array is initialized with a single member, the string ":"&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;name &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;PHRASES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHRASES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"Hail, &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

greetings Alex Jay Sam

&lt;span class="c"&gt;# Use array items from 1, upwards: `${varname[@]:1}`&lt;/span&gt;
&lt;span class="c"&gt;# to blat the initial placeholder&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;phrase &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHRASES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;:1&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"We say, &lt;/span&gt;&lt;span class="nv"&gt;$phrase&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# prints&lt;/span&gt;
&lt;span class="c"&gt;# We say, Hail, Alex!&lt;/span&gt;
&lt;span class="c"&gt;# We say, Hail, Jay!&lt;/span&gt;
&lt;span class="c"&gt;# We say, Hail, Sam!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does this make shell scripting "inferior"? No! The whole point of POSIX and POSIX-like shells is to be command-driven, and scripting enables re-running commands with some extra flair. &lt;a href="https://dev.to/taikedz/your-bash-scripts-are-rubbish-use-another-language-5dh7"&gt;I've talked about this before&lt;/a&gt;. Look at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# a contrived example, point is about the processing of program outputs, command-by-command&lt;/span&gt;
docker images | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;none&amp;gt;'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'s/  +/ /g'&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f3&lt;/span&gt; | xargs docker rmi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;runs &lt;code&gt;docker images&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;looks for &lt;code&gt;&amp;lt;none&amp;gt;&lt;/code&gt;-labelled images&lt;/li&gt;
&lt;li&gt;extracts the third field (the ID) line by line&lt;/li&gt;
&lt;li&gt;and converts the above into arguments for &lt;code&gt;docker rmi&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you're familiar with shell syntax, the above is easy to write - I did it in under 20sec. Doing the same with a more generalist programming language would take at least multiple lines, and if you wanted to keep it maintainable, a couple functions too.&lt;/p&gt;

&lt;p&gt;But for rich data processing, &lt;em&gt;shell scripting is not typically the best choice&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As for other gripes ...&lt;/p&gt;

&lt;p&gt;For the modularisation issue, in the script-based version of Alpacka I leveraged another tool I had, the &lt;a href="https://gitlab.com/taikedz/bash-builder" rel="noopener noreferrer"&gt;"bash builder"&lt;/a&gt; suite, which transpiles a custom syntax and resolves files from a &lt;code&gt;BBPATH&lt;/code&gt; library path, into a single deployable bash script. Again, I had to code this solution as a workaround to limitations with shell scripts. Again, shell scripts have idiosyncracies for gearing towards shell usage, not large-codebase usage. It has been fun to implement, but limitations still remain.&lt;/p&gt;

&lt;p&gt;Shell scripting argument parsing is pretty convoluted - you can use the &lt;code&gt;opts&lt;/code&gt; utility which behaves in mind-contorting ways, or reference positionals - a function's arguments are accessed the same way the script's arguments are, via &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, etc which prevents a function from directly accessing script args. It's possible - but there's a lot of faff to get it to work.&lt;/p&gt;

&lt;p&gt;Thus, the &lt;a href="https://github.com/taikedz/alpacka-ng" rel="noopener noreferrer"&gt;Alpacka/NG&lt;/a&gt; Go rewrite was born.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not python?
&lt;/h2&gt;

&lt;p&gt;I've written a fair bit of tooling python. It would have been my go-to for this kind of project (after my "bash as main language" phase...), but not for this.&lt;/p&gt;

&lt;p&gt;One of the issues with shell scripting remains with python: versioning, and command availability. At least it's not a question of variant usually, but between a newer script on older python (feature not available) or an older script on newer python (feature deprecated and removed), there's plenty of external dependency-ing that can go wrong.&lt;/p&gt;

&lt;p&gt;At work we got around this by using &lt;a href="https://pyenv.net/" rel="noopener noreferrer"&gt;pyenv&lt;/a&gt; , which went some way to working around the issue, but in some instances, pyenv would not even install (distro too old!)&lt;/p&gt;

&lt;p&gt;Compiling to binary solves this issue by just not having runtime dependencies (or so I thought - more on that later....!). But it holds by and large.&lt;/p&gt;

&lt;p&gt;This is more of an issue when trying to ship code to machines not under you control - in an enterprise environment, mandating specific distro versions and python versions etc is easier. Developing for the wilderness is another matter, and is the use case I have in mind for Alpacka - so it tracks. And if I need to install things first to support Alpacka correctly, purpose is defeated!&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Go
&lt;/h2&gt;

&lt;p&gt;Over the last few months I have been toying around with Go and only in the last month been actively trying to use it fully. Re-writing Alpacka was a good fit for me because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it compiles to single deployable file. I want to be able to just download it and start using it, no environment set up&lt;/li&gt;
&lt;li&gt;I want a set of package lists (package spec file) that apply under conditions, and I want alpacka to take care of it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The single-binary from Go answers the first, and the fact that I could not have the packages spec was due to the lack of complex types in Bash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package spec
&lt;/h3&gt;

&lt;p&gt;The spec I wanted to implement for looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;alpacka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;variants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VERSION_ID&amp;lt;=22, ID=~fedora&lt;/span&gt;
    &lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;common, fedora&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ID_LIKE=~debian&lt;/span&gt;
    &lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;common, debian&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ID_LIKE=~suse&lt;/span&gt;
    &lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;common, debian&lt;/span&gt;

  &lt;span class="na"&gt;package-groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;common&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
    &lt;span class="na"&gt;debian&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apache2&lt;/span&gt;
    &lt;span class="na"&gt;fedora&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;httpd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the catering to different names on different distros, and common names to share on all distros. Handy when hopping and wanting everything covered, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  How it went
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sub processes
&lt;/h3&gt;

&lt;p&gt;First off, running a sub-command in Go is pretty easy - a little more involved than in shell, no better or worse than in python. Because I did it a lot in this script (calls to package managers), I wrapped it in its own struct with some niceties: &lt;a href="https://github.com/taikedz/alpacka-ng/blob/v0.0.3/pakang/runner.go" rel="noopener noreferrer"&gt;runner.go&lt;/a&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// .OrFail() comes from the Result object, whih allows a shorthand exit-now to cut down on verbosity&lt;/span&gt;
&lt;span class="c"&gt;// -- because these calls would happen A LOT.&lt;/span&gt;
&lt;span class="n"&gt;RunCmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apt-get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"install"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"htop"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Could not run installation!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn't end up needing to pipe anything - but rather than "grep" and "cut" and "sed", instead we have actual programming functions that can operate on data types. It is indeed possible to use a subshell and write a command pipe, but I did not have need for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Argument parsing
&lt;/h3&gt;

&lt;p&gt;Next up was parsing arguments. I've written before about some of my basic frustrations with out-of-the-box Go, one of which is &lt;a href="https://dev.to/taikedz/baby-steps-with-go-3ibl#argument-parsing"&gt;around argument parsing&lt;/a&gt;. I've since solved this issue for myself in the form of my &lt;a href="https://github.com/taikedz/GoArgs" rel="noopener noreferrer"&gt;GoArgs&lt;/a&gt; package which offers short-flags and long-flags, positional argument unpacking, and additional handy options such as mode-switched flags.&lt;/p&gt;

&lt;p&gt;I know it's a solved problem, but I wrote my own argument parser myself because&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;supply chain security considerations - &lt;a href="https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-program/" rel="noopener noreferrer"&gt;if I can write it myself&lt;/a&gt;, why open myself up to supply chain attacks&lt;/li&gt;
&lt;li&gt;go language self-learning - re-writing Alpacka was not my first Go-venture ;-)&lt;/li&gt;
&lt;li&gt;go version releasing - I wanted to learn how to release a go module for re-use (and I did!)&lt;/li&gt;
&lt;li&gt;customisation - I had a specific idea as to what features I wanted, and what API I wanted, and one is best served by oneself. I did have to add customisations as I went about writing Alpacka-ng&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Publishing a Go module via hosted git repo
&lt;/h3&gt;

&lt;p&gt;Publishing a Go module is as simple as using version control (typically Git, not sure what else is supported) and tagging a commit with &lt;code&gt;v&amp;lt;x&amp;gt;.&amp;lt;y&amp;gt;.&amp;lt;z&amp;gt;&lt;/code&gt; - explicitly it needs the &lt;code&gt;v&lt;/code&gt; in the front, and three numbers. Go does the rest, and retains a hash for repeat-deployment verification. Note that the library project needs to declare itself with its intended publishing URL: set it up with &lt;code&gt;go mod init github.com/user/project&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A project depending on that module then just needs to add as it usually would - e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/user/project@v1.2.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and then start using it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/user/project"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallFunction&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;For comparison, Python has pip/conda/uv for adding external modules. Publishing them uses a &lt;code&gt;setup.py&lt;/code&gt; which is unwieldy, but so long as you have &lt;a href="https://gist.github.com/taikedz/6291300d2aa26a4e62e96364b6f10d00" rel="noopener noreferrer"&gt;a template&lt;/a&gt; for re-use, it's easy enough. You can add similarly &lt;code&gt;https://github.com/user/project@tag&lt;/code&gt; to a requirements.txt file to directly depend via git repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yaml and Supply Chain Trust
&lt;/h3&gt;

&lt;p&gt;Finally, I could implement the package list spec which I designed around YAML. First issue was to find a YAML package because Go does not ship one by default in the standard library. I've found that many languages do this - support JSON, but not YAML. Why? I know JSON is a very useful representation to serialise data, but YAML is a much more comfortable format for similarly serialised data that also needs to be &lt;em&gt;human editable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Plenty of tutorials exist online, all pointing to &lt;code&gt;gopkg.in/yaml.v3&lt;/code&gt; without a hint as to explaining&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what is &lt;code&gt;gopkg.in&lt;/code&gt;? why should I trust it?&lt;/li&gt;
&lt;li&gt;who wrote &lt;code&gt;yaml/v3&lt;/code&gt;? why should I trust them?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After some digging I found that the official Go project itself recognises &lt;code&gt;gopkg.in&lt;/code&gt; even so far as to making certain accommodations for its version notation. This is (at least in part) due to the fact that the site was the main solution for consistent package naming and version notating before the Go project implemented modules. It is a redirector that points to Github repos with a distinct short URL. Repos with a &lt;code&gt;gopkg.in/&amp;lt;PKG&amp;gt;.&amp;lt;VER&amp;gt;&lt;/code&gt; can be seen as an "official"/"blessed" package, whereas &lt;code&gt;gopkg.in/&amp;lt;USER&amp;gt;/&amp;lt;PKG&amp;gt;.&amp;lt;VER&amp;gt;&lt;/code&gt; are "unofficial"/"we don't verify these guys" sources. &lt;code&gt;gopkg.in/yaml.v3&lt;/code&gt; is an "official" package then, although the Github project it points to has been archived (read-only) since April 2025 (this year). Who knows what shall happen next...&lt;/p&gt;

&lt;p&gt;The official contents are published by Canonical Inc, the company behind Ubuntu. Based on this sleuthing, I was finally able to satisfy that the package was not completely random, and my "trust" in the "supply chain" is... acceptable. I now have a target, and a hash, but I'm pretty sure that can be circumvented by a later update on the v3 branch if the redirect gets modified... ah life on the open Internet...&lt;/p&gt;

&lt;p&gt;Supply chain attacks are on the rise, the &lt;a href="https://en.wikipedia.org/wiki/Npm_left-pad_incident#Immediate_effects" rel="noopener noreferrer"&gt;NPM leftpad incident&lt;/a&gt; not only highlighted the yanking of packages, but the ability of anyone to subsequently &lt;a href="https://www.drinchev.com/blog/alert-npm-modules-hijacked/" rel="noopener noreferrer"&gt;takeover the name of de-published packages&lt;/a&gt;. Similarly, &lt;a href="https://dev.to/protsenko/malicious-packages-in-npm-and-pypi-how-typosquatting-threatens-developers-134n"&gt;typo-squatting&lt;/a&gt; can lead to compromises lurking in the deep or just outright hosing a system.&lt;/p&gt;

&lt;p&gt;Beyond that, Unmarshalling Yaml/Json is a tad more cumbersome than parsing it in Python and descending dictionaries, but it does have the advantage of ensuring types all the way down.&lt;/p&gt;

&lt;p&gt;And then... I was done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking it on Alpine
&lt;/h2&gt;

&lt;p&gt;One of the compile targets was Alpine, though I ended up dropping this target since a/ Alpine's package manager is easy and b/ it is usually only used in Dockerfile specs/IaC in the first place.&lt;/p&gt;

&lt;p&gt;I discovered in this exercise however that binaries compiled on a GNU/Linux will not run on Alpine, due to linkages against different system runtime modules (different &lt;code&gt;libc&lt;/code&gt; implementations I think?). Huh. A runtime dependency in a "statically" compiled binary. There are nuances to everything after all.&lt;/p&gt;

&lt;p&gt;The result then being that an Alpine version of a Go program &lt;em&gt;must&lt;/em&gt; be compiled in an Alpine environment, otherwise you get a cryptic &lt;code&gt;bin/paf: not found&lt;/code&gt; error, despite the file being indeed there...! Using containers for build helped with that.&lt;/p&gt;

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

&lt;p&gt;Looking back at my work, it seems I have been able to implement this over the course of 8 days, a couple hours per day (and one full day in the mix too). I became more at-ease and fluent with the language as time progressed as one would expect as well. Could I have done this faster in python? Probably, but I would still have a runtime dependency. Could I have done it in bash scripting? With the added manifest, not a chance.&lt;/p&gt;

&lt;p&gt;It feels to me that Go is a credible alternative to both shell scripting and python given the requirements. However, I would still say that, with fluency, one would go faster with shell scripts for simple items (the build and install scripts are still shell), and faster in python for "throw it together" operations.&lt;/p&gt;

&lt;p&gt;Only You, however, can determine what's throwaway. At the risk of coining an abomination:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💩 Since bad code obviously needs rewritten, write bad python to get going; and if it must indeed grow: scrap it, and write good Go in its place. &lt;code&gt;/jk&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;😱&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>go</category>
      <category>bash</category>
      <category>python</category>
      <category>comparison</category>
    </item>
    <item>
      <title>Humanness at Work</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Wed, 21 May 2025 15:49:19 +0000</pubDate>
      <link>https://dev.to/taikedz/humanness-at-work-570p</link>
      <guid>https://dev.to/taikedz/humanness-at-work-570p</guid>
      <description>&lt;p&gt;I want to take a moment to talk about One-to-Ones at work. Send this to your manager. Send this to your director. It's important.&lt;/p&gt;

&lt;p&gt;When I took a role several years ago, I was introduced to a concept that blew my mind and continues to reverberate to this day: my manager scheduled a one-to-one with me &lt;em&gt;every week&lt;/em&gt; and kept to it - and if meetings caused a reschedule, he would set it for as soon as possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes we would talk about my progress, or how I talk to people.&lt;/li&gt;
&lt;li&gt;Sometimes we would talk about my expectations or frustrations.&lt;/li&gt;
&lt;li&gt;Sometimes we would talk about company directions or areas for my progress.&lt;/li&gt;
&lt;li&gt;Sometimes I would talk about what I needed from the organisation.&lt;/li&gt;
&lt;li&gt;Sometimes he would check in with my mental health and remind me that I could also be mindful of self care.&lt;/li&gt;
&lt;li&gt;And sometimes. He would keel me over with a litany of dad-jokes, we'd bond over the coffee machine about his llamas at home and his latest anti-fox solutions for his chicken coop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was regular. It made us more than colleagues. It made us human to eachother.&lt;/p&gt;

&lt;p&gt;Especially in a world where remote/hybrid work is becoming the norm, having regular check-ins, be they professional or casual, are of vital importance.&lt;/p&gt;

&lt;p&gt;A weekly half-hour one-to-one with the boss keeps things human. A boss who &lt;em&gt;knows how to be human&lt;/em&gt; is a keeper; one that just uses the exercise as a tick-box and ammunition is to be dropped. In my jobs, I have made a point of gathering team-mates over lunch - even to the point of everyone buying their sandwiches, and coming to eat around a desk. Discovering each other as humans goes much further than any ill-designed short-noticed "staff night out" or "team building event."&lt;/p&gt;

&lt;p&gt;In general for colleagues, a more personable one-to-one approach is advisable: every week, have a half-hour date with one of your colleagues. Be it going out to buy the sandwiches together, or indeed eating the lunch together, or just simply a half-hour call if remote teaming. Make a point of it. This week Alex. Next week Sam. Go beyond the transactional Teams call.&lt;/p&gt;

&lt;p&gt;Households, teams, organisations, operate better when everyone sees each other humanly, genuinely. Nobody needs to agree on all points - but being able to understand each other at human level allows us to work better together. And who knows - maybe find new friends.&lt;/p&gt;

&lt;p&gt;So set up a one-to-one with a colleague now. And for everyone on your team. You don't need HR to "Approve" this... or if you do... well... let's just say there are better companies out there.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>remote</category>
      <category>watercooler</category>
      <category>teambuilding</category>
    </item>
    <item>
      <title>What ((programming) language) should I learn this year, 2025 ?</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Wed, 15 Jan 2025 17:01:46 +0000</pubDate>
      <link>https://dev.to/taikedz/what-programming-language-should-i-learn-this-year-2025--meo</link>
      <guid>https://dev.to/taikedz/what-programming-language-should-i-learn-this-year-2025--meo</guid>
      <description>&lt;p&gt;It's a question that is evergreen, but especially prevalent at the turn of the year: what skills should I learn this year?&lt;/p&gt;

&lt;p&gt;It's not just programming languages either, there are a slew of areas of life where skills are desirable but you wonder how to go about it or whether it's worth the effort.&lt;/p&gt;

&lt;p&gt;And if there's anything I've learned it's not "should I learn it" but "how much does it cost to learn it?"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR - just set aside time to learn any that you feel curious about. It costs you little, and you gain so much from learning to think in different paradigms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  💸 Cost of starting
&lt;/h2&gt;

&lt;p&gt;(I know, I am digressing, bear with me ...)&lt;/p&gt;

&lt;p&gt;Some skills are more expensive to pick up, and wondering whether you want to spend a lot without even knowing if you'll be sticking with it is a reasonable reason for pause.&lt;/p&gt;

&lt;p&gt;For example, if you wanted to pick up a musical instrument skill, there's the outlay of buying or renting said instrument upfront. To learn piano, you need regular access to a piano for practice, and those things don't come cheap, and going all the way to a practice hall every time can quickly curb a beginner's enthusiasm; so it's fairly reasonable to &lt;em&gt;um&lt;/em&gt; and &lt;em&gt;ah&lt;/em&gt; about it. But if you wanted to pick up an instrument with a piano-layout keyboard (albeit limited), you could probably manage a &lt;a href="https://duckduckgo.com/?q=melodica&amp;amp;t=ffab&amp;amp;iax=images&amp;amp;ia=images" rel="noopener noreferrer"&gt;melodica&lt;/a&gt; and see if the layout works for you - it's cheap, it's portable, and a lot of beginner piano theory and tutorials apply to it.&lt;/p&gt;

&lt;p&gt;Conversely, there are skills which cost little to get started with - cooking certain types of foods if you already have a stove/oven, or take up drawing (pencils and eraser, and a stack of A4/letter paper is easy to come by), and then you can just scour youtube for a variety of tutorials - try drawing chibis to start with?.&lt;/p&gt;

&lt;p&gt;Similarly there are many options and approaches for learning foreign spoken languages, ranging from free (apps and meetups) to pay-for (courses) or even specialization (degrees) which you can approach little by little as you find your feet.&lt;/p&gt;

&lt;p&gt;Last year I took up foraging and fermenting, and whilst there was a little cost in books (I have many now) and jars (I just bought some more the other day), it was mostly a cheap outlay for a set of skills I take great joy from today. Mostly, gaining a reason and actual pleasure from heading out into the woods, even on a rainy day.&lt;/p&gt;

&lt;p&gt;It's not just about computers - anything you can do to spend time away from the screen is immensely important for your continued good health to come back refreshed 🌲&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 What Programming Language?
&lt;/h2&gt;

&lt;p&gt;But back to dev talk. What &lt;em&gt;programming language&lt;/em&gt; is worth learning ?&lt;/p&gt;

&lt;p&gt;I'll cut to the chase and answer this: ⭐ any you feel curious about ⭐ . If you can set aside 30min in any given day, or every other day, you'll get enough of a flavour of a language to decide whether you want to pursue it. Heck, dedicate an hour to the language and its base systems, and if you're already mad at it after that, just stop, and uninstall.&lt;/p&gt;

&lt;p&gt;Because, with very few exceptions, getting started with a new programming language is &lt;em&gt;near zero cost&lt;/em&gt;, in monetary expenses at least. Aside from the time you need to set aside, if you already program, you have the required equipment and skill to just launch into it.&lt;/p&gt;

&lt;p&gt;Sure, it may pay to read up on the languages that have piqued your interest upfront, and once you've done that you will probably have a good idea which ones you do want to dedicate an hour to and which are already just outright not a fit for you.&lt;/p&gt;

&lt;p&gt;And if you come away with a shortlist thinking "this one or that one or the other," I would wager that the obvious answer should be: &lt;strong&gt;all of them&lt;/strong&gt; , in sequence.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✂️ Narrowing Down
&lt;/h2&gt;

&lt;p&gt;It also helps to know what kind of ballpark use case you are aiming for. My use case requirements are &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;command line&lt;/li&gt;
&lt;li&gt;ideally, compiled&lt;/li&gt;
&lt;li&gt;preferably without external runtime requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My other use case (as a separate effort) is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;back end for simple websites/apps&lt;/li&gt;
&lt;li&gt;simple/minimal build and hosting requirements&lt;/li&gt;
&lt;li&gt;good standard library/reduce external dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last year I doubled-down on Zig, as idiosyncratic as it is to me coming from scripting languages (and very much because of it), and I am pursuing Go as well, as a nicer middle ground.&lt;/p&gt;

&lt;p&gt;Between what I have experienced from C and Zig, I am not even considering C at this point anymore. Maybe later, but I do not see the benefit, given my language selection as it stands. I had a quick look at Kotlin from afar (perusing how-tos and videos, and simply reading a quick install guide) and decided I had no interest.&lt;/p&gt;

&lt;p&gt;For web, PHP was also on the docket for a short moment, but I don't feel I want to go there yet; I feel more relevance looking first into Django and Flask before I return to PHP (I used to do php3 projects, way back when...). Gleam and Scala run on dedicated VMs and whilst in a production setting that's not a problem, I do want to make applications that can run on free-tier hosting, which PHP has had the advantage since the 90's ...&lt;/p&gt;

&lt;h2&gt;
  
  
  🔨 Mini-projects
&lt;/h2&gt;

&lt;p&gt;Once you get past the first hour of each language, I reckon there will be some you'll think "nope, I'm done here" - and that's fine. That's the whole point of this in the end. After which you're left perhaps with one or two languages that remain contenders for &lt;em&gt;Your Next Thing&lt;/em&gt;. What next?&lt;/p&gt;

&lt;p&gt;One of the questions I've heard from a couple of friends repeatedly is, "how do you even choose a side project?" My take is, what's a thing you wish there was a program for? What's the simplest thing that program would do?&lt;/p&gt;

&lt;p&gt;I live on the command line, so this question is usually easier for me, barring having to do more complex things (I don't (yet) do media processing, or have need to do rich GUI stuff). But I do often want to say organise and deduplicate a few reams of photos or MP3's (my backup drives are in disarray since forever and I need to wrangle them to sensibility...) , and I am often wishing websites would publish and list their content sensibly (web scraping and RSS feed corralling comes to mind).&lt;/p&gt;

&lt;p&gt;Try to think, how would a command line program do 80% of what you need to do? Or for GUI projects, how would you get the thing done with a couple simple widgets and buttons? And take it from there.&lt;/p&gt;

&lt;p&gt;Aim to scratch a particular itch 😖, reduce the feature set to minimum 🔪, and have at 💪.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;(As an example dump: I am currently trying to rewrite my bash-builder project (extending the &lt;a href="https://github.com/taikedz/lenker" rel="noopener noreferrer"&gt;lenker&lt;/a&gt;), I have a tarball-dependencies project inspired by Zig's &lt;code&gt;build.zig.zon&lt;/code&gt; file, did an &lt;a href="https://github.com/taikedz/os-release-q" rel="noopener noreferrer"&gt;&lt;code&gt;/etc/os-release&lt;/code&gt; reader&lt;/a&gt; for something simple, and pondered a &lt;a href="https://github.com/taikedz/pathctl" rel="noopener noreferrer"&gt;&lt;code&gt;PATH&lt;/code&gt; management utility&lt;/a&gt; . For web stuff, I have a player registry I ideated once when thinking about cross-server stuff for Luanti, but I have yet to properly sit down to. All of which I will likely try revisiting in various languages as the need arises.)&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📋 What languages for me this year?
&lt;/h2&gt;

&lt;p&gt;If you really want to see a language list from some nobody on t'interweb, here's where I'm at - this year I intend to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Continue with Zig and Go - I want to gain familiarity with a systems programming language, and a systemsy language that still has some extra fluff.&lt;/li&gt;
&lt;li&gt;Reignite my Lua skills with &lt;a href="https://love2d.org/" rel="noopener noreferrer"&gt;Love2D&lt;/a&gt;, and maybe return a little bit to &lt;a href="https://www.luanti.org/" rel="noopener noreferrer"&gt;Luanti&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Get more hours into Django (yeah not a language, but furthering my Python mastery)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎉 Voila
&lt;/h2&gt;

&lt;p&gt;It's a relatively low cost to entry to try out a programming language when you already have a computer and an Internet connection, and well worth sinking an hour or two each into multiple languages and trying to understand why they work the way they do, and what new ways of thinking they can bring to you.&lt;/p&gt;

&lt;p&gt;It's not "should I try X or Y" but "I've tried X and I've tried Y - how much more time shall I spend on each?" ⏲️&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>skills</category>
      <category>learning</category>
    </item>
    <item>
      <title>Simple Python Logging - and a digression on dependencies, trust, and Copy/pasting code</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Tue, 26 Nov 2024 12:18:36 +0000</pubDate>
      <link>https://dev.to/taikedz/simple-python-logging-and-a-digression-on-dependencies-trust-and-copypasting-code-229o</link>
      <guid>https://dev.to/taikedz/simple-python-logging-and-a-digression-on-dependencies-trust-and-copypasting-code-229o</guid>
      <description>&lt;p&gt;&lt;small&gt;&lt;a href="https://www.flickr.com/photos/ducakedhare/54109017061/in/datetaken-public/" rel="noopener noreferrer"&gt;Header Image (C) Tai Kedzierski&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Goto Snippet&lt;/p&gt;

&lt;p&gt;This post is opinionated.&lt;/p&gt;

&lt;p&gt;Python's default log setup is unhelpful; it works against the "batteries included" approach we have come to expect.&lt;/p&gt;

&lt;p&gt;From a useful log message, I want to know when, what level, and what information. I may want it on console, I may want it in a file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This should be simple&lt;/em&gt; - but in Python I end up every time having to look up how to create a full logging utility with custom file handling and string formatting. &lt;/p&gt;

&lt;p&gt;It &lt;em&gt;should&lt;/em&gt; be as simple as &lt;code&gt;logger = getLogger()&lt;/code&gt;, but the default behaviour for some unknown reason is to provide a completely useless formatting, and no shorthand for a sensible default.&lt;/p&gt;

&lt;p&gt;That or I need to download some pip package of unknown provenance, trust that it hasn't been name-hijacked, or doing some obfuscated exfilration. The &lt;a href="https://en.wikipedia.org/wiki/Npm_left-pad_incident" rel="noopener noreferrer"&gt;leftpad incident from 2016&lt;/a&gt; comes to mind, as well as the &lt;a href="https://jfrog.com/blog/revival-hijack-pypi-hijack-technique-exploited-22k-packages-at-risk/" rel="noopener noreferrer"&gt;Revival hijack attack from 2024&lt;/a&gt; which was essentially the same problem in a different repo system.&lt;/p&gt;

&lt;p&gt;In fact, &lt;em&gt;any user-repo without namespacing&lt;/em&gt; is vulnerable to this: Node's npm, Python's pip, Arch's AUR, Canonical's snap ... to name a handful who just let users upload whatever. Even namespacing isn't a guarantee of trust - I've come across projects that distribute their software through these channels not through the project's name, but via some arbitrary dev's monicker, raising doubt as to the authenticity of the package. I gave my thought process on how to decide on whether to trust a source &lt;a href="https://dev.to/taikedz/considering-syncthing-at-work-3pin"&gt;in a previous post&lt;/a&gt; on using syncthing in a work environment.&lt;/p&gt;

&lt;p&gt;External dependencies in user-controlled repos are the devil, and should only be considered when the solution to a problem is complex. And in general, simple solutions should just &lt;a href="https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-program/" rel="noopener noreferrer"&gt;exist directly in the code base&lt;/a&gt; - ideally self-written, but sometimes the problem &lt;em&gt;just&lt;/em&gt; strafes into the "cumbersome enough" space to make a dependency feel both reasonable and icky.&lt;/p&gt;

&lt;p&gt;The answer: write it once, stash it away in a Github gist or in a "useful snippets" repo of your own. Copy and paste.&lt;/p&gt;

&lt;p&gt;Copy Paste? Ew!&lt;/p&gt;

&lt;p&gt;"Copy and paste" of code probably sends alarm bells ringing for any seasoned coder. "Don't repeat yourself," "use a package manager," "write once, update everywhere." These are good instincts to have, but case-by-case, it is also good to know when copy-paste &lt;em&gt;is&lt;/em&gt; preferable.&lt;/p&gt;

&lt;p&gt;In this case, the requirement is to &lt;em&gt;avoid unnecessary external dependencies&lt;/em&gt; for a &lt;em&gt;simple solution to a simple need&lt;/em&gt; . In leftpad as with this mini-logger, the required code snippet is &lt;em&gt;short&lt;/em&gt; and &lt;em&gt;easy to understand&lt;/em&gt; ; it is no loss to reimplement if needed. It is also appropriately licensed (yes, it may be just a snippet; it remains however recommendable to ensure that what you are copying is indeed allowable. Be wary of copying random blobs of code.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Mini Logger Snippet
&lt;/h2&gt;

&lt;p&gt;I include below a code snippet for a mini-logger utility which allows for a single call with minimal configuration:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;LOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mylog&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SimpleLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;this is useful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which prints to console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2024-11-20 10:43:44,567 | INFO | mylog : this is useful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The mini-logger code
&lt;/h2&gt;

&lt;p&gt;Copy this into a &lt;code&gt;minilogger.py&lt;/code&gt; file in your project. Tada - no external dependency needed. Left untouched, it will remain the same forever. No name hijacking. No supply-chain injection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# For completeness:
# (C) Tai Kedzierski - Provided under MIT license. Go wild.
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;FORMAT_STRING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%(asctime)s | %(levelname)s | %(name)s : %(message)s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;ERROR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;
    &lt;span class="n"&gt;WARN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WARN&lt;/span&gt;
    &lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;
    &lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt_string&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FORMAT_STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WARNING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# log level here sets lower limit on all logs - hnce hard coded to DEBUG
&lt;/span&gt;        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;formatter_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Formatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt_string&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;files&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_add_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFormatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatter_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&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;console&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;_add_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&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;filepath&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;_add_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://mit-license.org/" rel="noopener noreferrer"&gt;MIT license&lt;/a&gt; essentially allows you to "do whatever you want with this." No strings attached.&lt;/p&gt;

&lt;p&gt;There we are. A simple log 🪵&lt;/p&gt;

</description>
      <category>python</category>
      <category>logging</category>
      <category>snippet</category>
    </item>
    <item>
      <title>Learning Zig : a Python dev's learning notes</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Sun, 13 Oct 2024 22:15:48 +0000</pubDate>
      <link>https://dev.to/taikedz/zooming-to-zig-tips-tricks-and-trip-ups-5676</link>
      <guid>https://dev.to/taikedz/zooming-to-zig-tips-tricks-and-trip-ups-5676</guid>
      <description>&lt;p&gt;&lt;small&gt;&lt;a href="https://flickr.com/photos/ducakedhare/4272530726/" rel="noopener noreferrer"&gt;Cover photo (C) Tai Kedzierski&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Scripting languages and System languages are two parts of a vast ecosystem. I wanted to cross to the other side to see what life is like there...&lt;/p&gt;

&lt;p&gt;Having trawled through a lot of reference material, I found some common-use concepts still lacking for the beginner, so this aims to stand as a jump pad for anyone else from a python/scripting starting out with systems languages in general, and Zig in particular.&lt;/p&gt;

&lt;h1&gt;
  
  
  Zig? ⚡
&lt;/h1&gt;

&lt;p&gt;Zig is the ace new kid on the block and, whilst still in its early days, is proving that it has a lot to offer. The release of &lt;a href="https://bun.sh/" rel="noopener noreferrer"&gt;the bun JS/TS runtime&lt;/a&gt; launched its name to the fore and developer interest has increased rapidly over the last two years - it debuted on &lt;a href="https://survey.stackoverflow.co/2023/#technology-admired-and-desired" rel="noopener noreferrer"&gt;StackOverflow's 2023 survey&lt;/a&gt; at an impressive initial 39.5% on the "admired" rating metric, and &lt;a href="https://survey.stackoverflow.co/2024/technology#admired-and-desired" rel="noopener noreferrer"&gt;the following year&lt;/a&gt; rose to &lt;strong&gt;73.8%&lt;/strong&gt; - well ahead of C's &lt;strong&gt;47.4%&lt;/strong&gt; , and only just tailing Rust's &lt;strong&gt;82.2%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I myself work predominantly with Python, a garbage-collected scripting language with lots of QOL features, and have been dabbling with Go (both sitting at a tidy 67% rating for the "admired" metric). Both occupy a same space of wanting to facilitate rapid development - but whereas Python offers a rich language feature set for flexibility and readability; Go offers a much more stripped back syntax with a focus on simplicity and efficiency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/taikedz/baby-steps-with-go-3ibl"&gt;I've coded in Go a little bit&lt;/a&gt;, and was considering basing my next efforts there, as it feels much more approachable for a script language specialist; but I felt it would be a much better horizon-widener to dive properly into a systems programming language. &lt;a href="https://dev.to/taikedz/from-python-to-rust-notes-from-a-simple-rust-starter-project-3362"&gt;I tried to get on board with Rust&lt;/a&gt;, but felt its hype and promises ended up not delivering enough against the difficulty to work with it. The worst for me was the amount of code nesting its management entailed, especially managing error cases against option-matching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation and Learning Resources
&lt;/h2&gt;

&lt;p&gt;There are a number of good learning resources for the basics - the order in which I stepped through was to first read the language reference. Following some advice I saw for Rust, I read through the documentation first whilst resisting the temptation to experiment too much.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ziglang.org/documentation/0.13.0/" rel="noopener noreferrer"&gt;Language reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I then started looking through the Ziglings excercises one by one, and finding them to be pretty good at gently easing the learner through basic concepts. After exercise 25 or so, I decided that perhaps I didn't need to go through the rest of it and decided to rewrite my Go project &lt;a href="https://github.com/taikedz/os-release-q" rel="noopener noreferrer"&gt;Os-Release Query&lt;/a&gt; . I had written it in Go as a beginner in about two or three sessions to completion, so I reckoned it was a simple enough to proceed with. It took me about two weeks with several sessions of learning and stumbling.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ziglings.org/" rel="noopener noreferrer"&gt;Ziglings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I contended with a few teething difficulties, I found myself frequently going to Zig.guide for simple examples and explanations of usage - specifically the &lt;code&gt;ArrayList&lt;/code&gt; and &lt;code&gt;Allocators&lt;/code&gt; pages, the former being key for doing general file reading tasks. My first mistake was to think about string arrays similarly as in Python or in Go (see "Strings and ArrayLists" below).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://zig.guide/" rel="noopener noreferrer"&gt;Zig.guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, sensing I was needing a bit more guidance, I found myself stepping through several excellent videos from &lt;em&gt;Dude the Builder&lt;/em&gt;'s (José Colón) Zig in Depth series. Having read through the standard documentation, and cross-referencing against the standard library documentation, Colón's guidance was the last missing piece for getting proper progress.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLtB7CL7EG7pCw7Xy1SQC53Gl8pI7aDg9t" rel="noopener noreferrer"&gt;Zig in Depth on Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ziglang.org/documentation/0.13.0/std/" rel="noopener noreferrer"&gt;Standard library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And of course, web searching and StackOverflow filled in specific gaps, notably I kept coming back to a &lt;a href="https://stackoverflow.com/questions/66527365/how-to-concat-two-string-literals-at-compile-time-in-zig#66665672" rel="noopener noreferrer"&gt;string concatenation answer&lt;/a&gt; on SO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Arrays, Slices, Strings and ArrayLists
&lt;/h3&gt;

&lt;p&gt;Unless you've worked in C before, you come in for a rude awakening to discover that there is no native language construct for a "string" (beyond a double-quote notation of static literals). Most modern languages have them. All scripting languages have them in some form. Go and Rust have them. But C and Zig share the same principle: there is no string, only sequences of bytes. Whilst C has a "character" &lt;code&gt;char&lt;/code&gt; type, Zig takes it a step further by only referencing an unsigned integer type to represent a byte.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;
&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="c"&gt;// or even&lt;/span&gt;
&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cs"&gt;# Zig&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hi&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;u8&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the Zig side, note the &lt;code&gt;const&lt;/code&gt; on the array type notation - a lot of functions which receive a "string" as parameter best makes the assumption that the data being received could be a literal - in this case, it's hard-coded and unmutable. If a function is defined as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the type cannot be a string literal, but instead requires that the item be mutable, that it can change - pointers into heap memory locations most frequently.&lt;/p&gt;

&lt;p&gt;There are many subtleties to this, and I mainly worked against &lt;a href="https://zig.news/david_vanderson/beginner-s-notes-on-slices-arrays-strings-5b67" rel="noopener noreferrer"&gt;an item from Zig.news&lt;/a&gt; to keep myself sane.&lt;/p&gt;

&lt;p&gt;I made &lt;a href="https://stackoverflow.com/q/79033088/2703818" rel="noopener noreferrer"&gt;an early mistake&lt;/a&gt; to think about loading a ASCII file lines, into an array or array of bytes, whereas in fact what I needed was an &lt;a href="https://zig.guide/standard-library/arraylist/" rel="noopener noreferrer"&gt;ArrayList&lt;/a&gt; - a dynamically growable and iterable sequence of items - of slices, which are sort of 'views' (with a pointer and length) onto arrays (a fixed-length sequence of a given type).&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack and Heap
&lt;/h3&gt;

&lt;p&gt;Stack vs Heap is a key concept in any language where you are made to manually manage memory, there's no way around it really, and coming in from GC languages, I had to be disabused of some simplistic notions.&lt;/p&gt;

&lt;p&gt;Understanding the stack and the heap was a bit more than "heap is big and persistent/stack is small and throwaway". It also goes hand-in-hand with reasoning on passing by value or reference, which in turn is more than "did you pass through a native literal type or a pointer." &lt;a href="https://www.geeksforgeeks.org/stack-vs-heap-memory-allocation/" rel="noopener noreferrer"&gt;Geeks for Geeks&lt;/a&gt; goes over the principle from a mainly C/C++ point of reference, whereas &lt;a href="https://www.openmymind.net/learning_zig/stack_memory/" rel="noopener noreferrer"&gt;OpenMyMind.net&lt;/a&gt; walks through it specifically with Zig examples.&lt;/p&gt;

&lt;p&gt;I am not in a position to explain its nuances myself as I am still learning, but the shift in understanding these was very much crucial for comprehending what I was doing in my project. I can only recommend reading up on those two sites as a starting points as mandatory reading before proceeding further.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.geeksforgeeks.org/stack-vs-heap-memory-allocation/" rel="noopener noreferrer"&gt;Geeks for Geeks&lt;/a&gt; - Stack vs Heap with C focus&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.openmymind.net/learning_zig/stack_memory/" rel="noopener noreferrer"&gt;Open My Mind&lt;/a&gt; - Stack vs Heap with Zig focus&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Allocators
&lt;/h3&gt;

&lt;p&gt;One of the key features of Zig is its use of allocators, which is one of the major improvements in memory management assistance we get from the compiler and its debug-mode builds. It is still possible to double-free and leak memory from improperly-written code - but using the debug build (the default build mode) causes exceedingly useful stack traces to show the origins of leaked/non-freed memory and give you an early chance of catching and remediating memory problems.&lt;/p&gt;

&lt;p&gt;The General Purpose Allocator can be the go-to reference for pretty much anything if you just want to get started. Both &lt;a href="https://zig.guide/standard-library/allocators/" rel="noopener noreferrer"&gt;Zig Guide&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=I_ynVBs66Oc&amp;amp;list=PLtB7CL7EG7pCw7Xy1SQC53Gl8pI7aDg9t&amp;amp;index=21&amp;amp;pp=iAQB" rel="noopener noreferrer"&gt;Dude the Builder&lt;/a&gt; give an excellent run down on how to use them - once you see them in use a couple of times, they usually feel mostly plug-and-play.&lt;/p&gt;

&lt;p&gt;Zig makes a promise - and sets a standard/best-practice - of no hidden allocations: if a function does not take an allocator instance, or a type is not initialized with one, then it promises no allocation to happen. Likewise, library creators are encouraged to abide by the same principle. This goes a long way to ensuring no nasty memory leak surprises deep in a project's dependencies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://zig.guide/standard-library/allocators/" rel="noopener noreferrer"&gt;Zig Guide&lt;/a&gt; on Allocators&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=I_ynVBs66Oc&amp;amp;list=PLtB7CL7EG7pCw7Xy1SQC53Gl8pI7aDg9t&amp;amp;index=21&amp;amp;pp=iAQB" rel="noopener noreferrer"&gt;Zig in Depth&lt;/a&gt; on Memory management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Structs and Methods
&lt;/h3&gt;

&lt;p&gt;Unlike in C, structs can come with their own dedicated functions, or methods, firmly attached to the types they are associated with. Like in Python, if the first argument is a &lt;code&gt;self&lt;/code&gt; reference, it can be used on an instance, but without it, it can only be used from an uninstantiated struct type.&lt;/p&gt;

&lt;p&gt;This gives the flexibility of some type-specific operations that are carried through a &lt;code&gt;instance.method()&lt;/code&gt; notation, but avoids the pitfall of object-orientation inheritance deluges by just not permitting them.&lt;/p&gt;

&lt;p&gt;I find this notationally and conceptually convenient, and a good introduction to the idea of "composition over inheritance" that is becoming more and more popular. Stuff that, &lt;code&gt;JavaDeepInheritanceSingletonFactoryInstantiatorHelper&lt;/code&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build System
&lt;/h2&gt;

&lt;p&gt;The build system in Zig is interesting. I cannot claim to fully understand it much at all, except that to say I am glad I don't have to contend with Makefiles. Whether it is in fact better remains to be seen (for me), but I am going to keep exploring.&lt;/p&gt;

&lt;p&gt;One thing I do enjoy very much however is the &lt;code&gt;build.zig.zon&lt;/code&gt; file, and how it manages dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;zg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://codeberg.org/dude_the_builder/zg/archive/v0.13.2.tar.gz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"122055beff332830a391e9895c044d33b15ea21063779557024b46169fb1984c6e40"&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="py"&gt;module2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://site/path/item2.tar.gz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1210abcdef1234567891"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using other peoples' libs
&lt;/h3&gt;

&lt;p&gt;There is no central package manager in Zig - simply point at tarball URLs online and fetch them.  &lt;a href="https://ziglist.org/" rel="noopener noreferrer"&gt;ZigList.org&lt;/a&gt; tracks libraries on Github and Codeberg (primary host of Ziglings and a preferred space for some Zig creators), and if you do publish one on either platform, it should eventually get picked up.&lt;/p&gt;

&lt;p&gt;The hash however is not a hash of the tarball, but a cumulative hash of each exported item from the package.&lt;/p&gt;

&lt;p&gt;Either way, there is an interesting aspect of the system: after performing &lt;code&gt;zig build&lt;/code&gt;, any dependencies are downloaded and unpacked to &lt;code&gt;~/.cache/zig/p/&amp;lt;hash&amp;gt;/...&lt;/code&gt; . There are two aspects that I came up against in playing with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You cannot easily calculate the hash in advance yourself&lt;/li&gt;
&lt;li&gt;If a hash exists already, then the tarball is not re-downloaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when I wanted to add my second module, I needed a placeholder hash. I blindly re-used the hash from the prior module and could not figure out why it wouldn't a/ prompt me for hash re-validation on my bogus hash, and b/ didn't find the files from the second module.&lt;/p&gt;

&lt;p&gt;Eventually after trawling the net I found &lt;a href="https://ziggit.dev/t/how-to-package-a-zig-source-module-and-how-to-use-it/3457" rel="noopener noreferrer"&gt;two&lt;/a&gt; &lt;a href="https://mattfreire.blog/posts/how-to-build-and-use-zig-packages" rel="noopener noreferrer"&gt;resources&lt;/a&gt;, I figured that I should simply copy an existing hash and then mangle the last few bytes of it. The standard documentation is admitted by the core team to not yet fully be there yet - which I understand since the dust isn't yet completely settled on the final forms of many things, and a lot is still moving about, so other peoples' blogs are a godsend...&lt;/p&gt;

&lt;p&gt;Using a library involves adding some code in your &lt;code&gt;build.zig&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;    &lt;span class="c"&gt;// Find the dependency named "zg" as declared in build.zig.zon&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;dep_zg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"zg"&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="c"&gt;// Get the `CaseData` module from the `zg` dependency&lt;/span&gt;
    &lt;span class="c"&gt;//   and register as importable module "zg_CaseData"&lt;/span&gt;
    &lt;span class="c"&gt;// In project code, use @import("zg_CaseData")&lt;/span&gt;
    &lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;root_module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addImport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"zg_CaseData"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dep_zg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CaseData"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usually the README of the library will give you more detailed instructions and, hopefully, the hash to use as well. The above was an example for using Dude the Builder's &lt;a href="https://codeberg.org/dude_the_builder/zg/" rel="noopener noreferrer"&gt;zg library&lt;/a&gt; for UTF-8 string handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating your own lib
&lt;/h3&gt;

&lt;p&gt;One item I created for my project was an ASCII file reader and, knowing that I would likely want to re-use that code, I decided to try to make my own library.&lt;/p&gt;

&lt;p&gt;The most minimal snippet for creating a library in Zig 0.13.0 consists of a source directory, a &lt;code&gt;build.zig.zon&lt;/code&gt; to declare relevant items, and a &lt;code&gt;build.zig&lt;/code&gt; for executing the build when it is imported:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;build.zig.zon&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"build.zig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"build.zig.zon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;build.zig&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;standardTargetOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;optimize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;standardOptimizeOption&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;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my-lib"&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="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;root_source_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/main-file.zig"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;optimize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optimize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Follow then the above for importing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;It's only the beginning for me with Zig and so far, it has been rewardingly challenging. Going on this little escapade has taught me much about how to design for memory efficiency (I have not achieved it - but I know &lt;em&gt;how&lt;/em&gt; my Python-oriented code design would not fly in a performance-oriented space).&lt;/p&gt;

&lt;p&gt;And that's growth. 🌱&lt;/p&gt;

</description>
      <category>zig</category>
      <category>devjourney</category>
      <category>learning</category>
    </item>
    <item>
      <title>Beyond "Hello World" - comparing starter code in C, Rust, Python, TypeScript and more</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Thu, 15 Aug 2024 16:33:44 +0000</pubDate>
      <link>https://dev.to/taikedz/polydev-a-better-hello-world-for-polyglot-devs-37p2</link>
      <guid>https://dev.to/taikedz/polydev-a-better-hello-world-for-polyglot-devs-37p2</guid>
      <description>&lt;p&gt;&lt;small&gt;&lt;a href="https://flickr.com/photos/ducakedhare/53480037375/" rel="noopener noreferrer"&gt;Cover image (C) Tai Kedzierski&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR : The classic "Hello World" doesn't show enough of a language to get a flavour for it - in this post we explore the same example written in several languages for comparison. "Hello Y'All" is a simple example that exercises more of a language. How does the "Hello Y'All" example work in your favorite languages?&lt;/p&gt;

&lt;p&gt;Disclaimer: none of the code here is intended to be "idiomatic" or "optimal". I'm a learner especially of the systems languages myself. Any suggestions for correction and improvement are welcome, and possibly even applied if compelling.&lt;/p&gt;

&lt;p&gt;The examples in this article have been posted at &lt;a href="https://github.com/taikedz/hello-yall" rel="noopener noreferrer"&gt;https://github.com/taikedz/hello-yall&lt;/a&gt; . A yet-to-be-done "&lt;a href="https://github.com/taikedz/hello-yall/tree/main-hinet" rel="noopener noreferrer"&gt;advanced example&lt;/a&gt;" is in the works as well&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a id="top"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hello Y'All basics&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Bash&lt;/li&gt;
&lt;li&gt;TypeScript via Bun&lt;/li&gt;
&lt;li&gt;PHP for Web&lt;/li&gt;
&lt;li&gt;C&lt;/li&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;Zig&lt;/li&gt;
&lt;li&gt;Rust&lt;/li&gt;
&lt;li&gt;Lua&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;Groovy&lt;/li&gt;
&lt;li&gt;Perl&lt;/li&gt;
&lt;li&gt;Extended Bash for Bash Builder&lt;/li&gt;
&lt;li&gt;Outro&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"Hello World" is the classic example program every new user is exhorted to write: superficially it serves as a way of showing how easy it is to do a basic task in the language; but it also serves as a simple way to check that the base tools are installed.&lt;/p&gt;

&lt;p&gt;For example, just making sure python is installed properly, one can write the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# some pythonfile like "spam.py"
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python spam.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a demonstration of how easy it is to get started, it contrasts with the likes of Java quite directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// MUST be "HelloWorld.java" file - public class name must match the file name&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hellow World!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to compile and run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javac HelloWorld.java
&lt;span class="c"&gt;# Produces a HelloWorld.class&lt;/span&gt;

&lt;span class="c"&gt;# To run it though, don't include ".class" !&lt;/span&gt;
java HelloWorld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Arguably, it's a good &lt;em&gt;tooling check&lt;/em&gt;, but it says little about how easy it is to do some basic things in a language.&lt;/p&gt;

&lt;p&gt;The one thing that always costs me time in getting started with any language is navigating its intricacies on splicing functions out to other files locally - and then importing them. Another is just wanting to see a simple example of how some basic flow works in the language: calling a function, returning, concatenating strings, and a simple iteration.&lt;/p&gt;

&lt;p&gt;&lt;a id="helloyall"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello Y'All
&lt;/h2&gt;

&lt;p&gt;I'd like to propose the following as a good reference example to showcase basic functionality in a single page - one that should be a very basic challenge, but with enough in it to allow a seasoned developer to &lt;em&gt;see&lt;/em&gt; the basic features, and appreciate the tutorials properly from there.&lt;/p&gt;

&lt;p&gt;So here's a "Hello Y'All" program to implement along the following rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The example takes at least one command line argument, and handles the event of no-arguments&lt;/li&gt;
&lt;li&gt;The example requires a function to be placed in a second file in a subfolder&lt;/li&gt;
&lt;li&gt;The function returns a value&lt;/li&gt;
&lt;li&gt;The example loops over CLI arguments, calling one at a time to the function, and each time prints the returned value, concatenated to other text&lt;/li&gt;
&lt;li&gt;Include the overall bare-minimum instructions include how to build the program (if necessary) and run it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why these requirements ? They showcase some of the basic features every language should support, for one; but also if you've already got a couple of languages under your belt, it is helpful to get a more holistic sense of the language's design and approach in one go, in a way that allows consistent comparison across languages.&lt;/p&gt;

&lt;p&gt;We will see over the next few examples that splitting code into local files is not always intuitive - every language has its way of handling importing, according to the architectural/environmental constraints of its time and/or target use-case. This is the main reason I was compelled to lay out a base example principle and write this post. Both in Rust and Go, I found myself mired in a hell of answers on "how to import external packages" and needless hunting for the answer to "how to import a local file."&lt;/p&gt;

&lt;p&gt;&lt;a id="python"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Python
&lt;/h2&gt;

&lt;p&gt;Python makes importing local files very simple, both syntactically and operationally - part of the "batteries included" approach. For sanity, I recommend &lt;code&gt;PYTHNOPATH&lt;/code&gt; point to the directory &lt;em&gt;containing&lt;/em&gt; the top level folder, always; it is usually optional as python does try to resolve things automatically, but sometimes it just needs the &lt;code&gt;PYTHONPATH&lt;/code&gt;. I only learned recently that &lt;code&gt;__init__.py&lt;/code&gt; files were optional ...&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;./hey.py&lt;/code&gt; file with these contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stuff.hello&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No arguments specified!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
    &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;./stuff/hello.py&lt;/code&gt; file with these contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Good practice to ensure python knows where to resolve top-level imports from&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Run it&lt;/span&gt;
python hey.py Jay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="bash"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Bash
&lt;/h2&gt;

&lt;p&gt;Bash is a language, that few really take the time to learn properly. Lots of unwieldy and unmaintainable bash scripts get written, which is a shame since... it typically is also code that holds up your business. Give it more love. ❤️&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./hey.sh&lt;/code&gt; put this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Imports the file contents ; all tokens in the file are added to the global scope&lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;stuff/hello.sh

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No arguments supplied"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

for &lt;/span&gt;name &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;phrase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;hello_greet &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$phrase&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;./stuff/hello.sh&lt;/code&gt; write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hello_greet&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# Arguments to functions are positional&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash hey.sh Jay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;source&lt;/code&gt;-ing is specifically relative to the current working directory! Source-ing from an already-sourced file is unreliable at best. For this reason, there is not much of a habit of splitting code into files where bash scripts are involved, and was the impetus behind writing bash-builder&lt;/p&gt;

&lt;p&gt;&lt;a id="bun-ts"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript via Bun
&lt;/h2&gt;

&lt;p&gt;I don't think I could get away with not including TypeScript on this list (I am forgoing trying to deal with JavaScript). And I certainly don't want to deal with discussing NodeJS and npm.&lt;/p&gt;

&lt;p&gt;Bun makes dealing with the JavaScript ecosystem easier, and removes the need for a lot of the independently existing standard tools. &lt;code&gt;node&lt;/code&gt;/&lt;code&gt;nodejs&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; commands can be replaced by &lt;code&gt;bun&lt;/code&gt; as a command, and conflicting requirement dependencies don't crop up. As a newcomer to it, do yourself a favour.&lt;/p&gt;

&lt;p&gt;Write in &lt;code&gt;./hey.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;greet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./stuff/hello.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please supply names !&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in &lt;code&gt;./stuff/hello.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this through bun:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun hey.ts Alex Sam Jay Pat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to compile it down to plain JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun build hey.ts &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; hey.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just be warned that in JavaScript and TypeScript, &lt;code&gt;[7,-2,6,-5].sort() == [ -2, -5, 6, 7 ]&lt;/code&gt; is a reality. It's not the only &lt;a href="https://www.destroyallsoftware.com/talks/wat" rel="noopener noreferrer"&gt;madness still around in 2024&lt;/a&gt; in the language. This should have been specified out by now, surely...&lt;/p&gt;

&lt;p&gt;&lt;a id="web-php"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Server PHP
&lt;/h2&gt;

&lt;p&gt;PHP has received much hate over the years, but let's not forget that we wouldn't have the Web of today without it (MediaWiki, WordPress and facebook are the notable projects that got a head start with it), and free tier hosting. You can be up and running with a website and even a working proof of concept business using PHP and a free webhosting tier faster than with any other language - instead of chaining yourself to &lt;em&gt;excessively&lt;/em&gt; "flexible" &lt;strong&gt;billing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This example takes a slightly different form, assuming the base case is in fact to run as a server script - so we'll retrieve from the GET request's query map, rather than iterating a list.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./hey.php&lt;/code&gt; write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="s2"&gt;"stuff/hello.php"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Give me a query!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$place&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hello_greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$place&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$phrase&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;./stuff/hello.php&lt;/code&gt; write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;hello_greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Hello &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="nv"&gt;$origin&lt;/span&gt;&lt;span class="s2"&gt; !"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload these to your web server hosting root (usually a &lt;code&gt;www/&lt;/code&gt; folder), and visit your site. Assuming it's served at &lt;code&gt;http://hosting.tld/~you&lt;/code&gt; then you would go to &lt;code&gt;http://hosting.tld/~you/hey.php?Kim=Korea,Sam=Sweden&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will simply write the greetings in the web page.&lt;/p&gt;

&lt;p&gt;&lt;a id="c"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  C
&lt;/h2&gt;

&lt;p&gt;Ah C. The gold standard of programming, besieged on all sides by upstarts. Zig, Rust, Go, all vying to be "the next C". And for understandable reason - so many catastrophic bugs and security issues stem from the mismanaged memory and ill-conceived pointer arithmetic.&lt;/p&gt;

&lt;p&gt;But, it is still a much needed and much beloved language, and essential in embedded programming. Perhaps Zig or Rust will replace it there, one day. But what is sure is that it is not leaving the party any time soon.&lt;/p&gt;

&lt;p&gt;Write a &lt;code&gt;./hey.c&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"stuff/hello.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// There is always at least one arg at argv[0], the program's name&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No arguments supplied&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello_greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// For completeness, we note here that any allocated memory&lt;/span&gt;
      &lt;span class="c1"&gt;//     MUST be deallocated - and ONCE only !&lt;/span&gt;
      &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then write a &lt;code&gt;./stuff/hello.c&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;hello_greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Constant, on the stack&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;base_hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Because we're returning the data out of a function,&lt;/span&gt;
    &lt;span class="c1"&gt;//   we need it on the heap&lt;/span&gt;
    &lt;span class="c1"&gt;//   The +1 is for the null-terminator on the end of the string&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;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_hello&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;strcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_hello&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;strcat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;phrase&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;C requires using header files &lt;code&gt;.h&lt;/code&gt; - one doesn't import source files directly, but instead you compile all the source files as binary, &lt;em&gt;import the headers&lt;/em&gt; as a way of resolving symbols. I don't have the ability to discuss the itnernals of this from a compiler perspecitve, but it is done this way for consistency : if you are including a pre-compiled library from elsewhere, you need a header file to tell you and the compiler what's actually available. I think.&lt;/p&gt;

&lt;p&gt;Write &lt;code&gt;stuff/hello.h&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// We guard against multi-inclusion by setting a one-time declared name&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef HELLO_H_
#define HELLO_H_
&lt;/span&gt;
&lt;span class="c1"&gt;// This tells the compiler that it should expect to find such a&lt;/span&gt;
&lt;span class="c1"&gt;//   function defined in the binary code that is being linked&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;hello_greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cp"&gt;#endif // HELLO_H_
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# See that we _compile_ the source files&lt;/span&gt;
&lt;span class="c"&gt;#   even though we are '#include'-ing header files&lt;/span&gt;
gcc &lt;span class="nt"&gt;-o&lt;/span&gt; hey hey.c stuff/hello.c

./hey Jay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the pretenders to the throne below ...&lt;/p&gt;

&lt;p&gt;&lt;a id="go"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Go
&lt;/h2&gt;

&lt;p&gt;I've seen Go be ascribed a number of lofty goals - a better C (not quite, especially with garbage-collection pauses), a replacement for Python (it's more performant, but much less friendly syntactically), and a replacement for shell scripting (I can kinda see that, if I squint hard enough).&lt;/p&gt;

&lt;p&gt;All imports are done from paths along the &lt;code&gt;GOPATH&lt;/code&gt; (and from the current project as discussed below) which usually points to a single directory, usually in &lt;code&gt;~/.go&lt;/code&gt; - not entirely sure why that is, as different projects will usually have different dependency needs - but that's the convention. You can of course change the &lt;code&gt;GOPATH&lt;/code&gt; as required, but that is neither necessary nor in scope for this example - it should fully irrelevant. If the compiler spits out something about not finding something on the GOPATH, the example (or your copying of it) should be suspected first...&lt;/p&gt;

&lt;p&gt;Your project needs to be initialised - in the top level of the project, do &lt;code&gt;go mod init $module_name&lt;/code&gt; , for example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go mod init net.myname.greeter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... conventionally using a reverse domain notation.&lt;/p&gt;

&lt;p&gt;The simple way of splitting code into several files is to simply write several &lt;code&gt;*.go&lt;/code&gt; files, all with &lt;code&gt;package main&lt;/code&gt; declarations, and running &lt;code&gt;go build -o my-app src/*.go&lt;/code&gt; . All symbols from these files will be directly available in the scope of any &lt;code&gt;main&lt;/code&gt;-package file. As a build requirement, &lt;em&gt;all files must be in the same directory&lt;/em&gt;. In this mode, it's not possible to store some files into subfolders.&lt;/p&gt;

&lt;p&gt;To get past the same-dir restriction and be able to place our greeter in its own folder, we need to create a submodule - specifically we are creating an explicit module under a different &lt;code&gt;package&lt;/code&gt; declaration.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./src/hey.go&lt;/code&gt; write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net.myname.greeter/src/stuff"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please supply arguments!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stuff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The module is created in a subfolder, and the main file must share the name of its parent folder.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;src/stuff/stuff.go&lt;/code&gt; write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;stuff&lt;/span&gt;

&lt;span class="c"&gt;// Because this function is to be used from outside the `stuff` package&lt;/span&gt;
&lt;span class="c"&gt;//    it needs to be Capitalised.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&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;return&lt;/span&gt; &lt;span class="s"&gt;"Hello "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go build src/hey.go

./hey Alex Sam

&lt;span class="c"&gt;# To just run without storing a build file:&lt;/span&gt;

go run src/hey.go Alex Sam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To add more files and functions to &lt;code&gt;stuff/&lt;/code&gt; , simply add the &lt;code&gt;./stuff/*.go&lt;/code&gt; files, all with &lt;code&gt;package stuff&lt;/code&gt; declarations. All files with the same &lt;code&gt;package stuff&lt;/code&gt; declaration will be able to use eachothers' symbols within the same &lt;code&gt;stuff&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;&lt;a id="zig"&gt;&lt;/a&gt;🔝&lt;/p&gt;

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

&lt;p&gt;From the little experimentation I've been doing, Zig seems to be the most likely contender in the race to replace C. I've not yet properly sat down to do a mini-project, so this &lt;em&gt;Hello Y'All&lt;/em&gt; example is going to be the most complete amount of active work I'll have done...&lt;/p&gt;

&lt;p&gt;The whole "allocators" pattern takes getting used to and was arguably the item I had to spend most time on. &lt;a href="https://zig.guide/standard-library/allocators/" rel="noopener noreferrer"&gt;There are several types of allocators&lt;/a&gt; (many more than in that article), and choosing one is no doubt an expression of sagacity. No doubt the neophyte would best be served by using the General Purpose Allocator as they start out. There's a few patterns, most generically the &lt;code&gt;alloc&lt;/code&gt;/&lt;code&gt;free&lt;/code&gt; pattern. If creating memory for structs, it's &lt;code&gt;var thing = allocator.create(your_struct) ; defer allocator.destroy(thing)&lt;/code&gt; . If it's an arena allocator for short-lived one-run programs, &lt;code&gt;arena_alloc.init()&lt;/code&gt; the item, and then &lt;code&gt;defer arena_alloc.destroy()&lt;/code&gt; the whole thing at the end of the progam.&lt;/p&gt;

&lt;p&gt;I do not claim to have grasped the subtleties at this point. The following code may yet be suboptimal. On the plus side... no header files !&lt;/p&gt;

&lt;p&gt;Write one file &lt;code&gt;hey.zig&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stuff/hello.zig"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStdOut&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c"&gt;// We need to manage the allocator in the very space we are going to call its free/destroy from&lt;/span&gt;
    &lt;span class="c"&gt;// we can't confine it easily to another function, so it feels a little cluttered ...&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;gpa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GeneralPurposeAllocator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{}){};&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;allo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gpa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gpa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deinit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argsAlloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argsFree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;len&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please specify arguments!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;:[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&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="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Because hello.greet creates the data and chucks it back out, we pass in&lt;/span&gt;
        &lt;span class="c"&gt;//   the allocator, so that we can retain responsibility for freeing&lt;/span&gt;
        &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;allo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{s}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then write &lt;code&gt;./stuff/hello.zig&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&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;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AllocPrintError&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Pass-down an allocator. All standard library functions which need&lt;/span&gt;
    &lt;span class="c"&gt;//  heap space will take an allocator, instead of using their own&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allocPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;allo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Hello, {s}!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;phrase&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;Then compile and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Compile&lt;/span&gt;
zig build-exe hey.zig

&lt;span class="c"&gt;# Run&lt;/span&gt;

./hey
./hey Sam Pat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="rust"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust
&lt;/h2&gt;

&lt;p&gt;Rust's documentation is a bit light on the explanations of splitting code out into folders, but I got there eventually - not sure I remember how, so I cannot offer any links.&lt;/p&gt;

&lt;p&gt;Rust is &lt;em&gt;very&lt;/em&gt; fussy when it comes to types, and probably one of the biggest gripes I have with it is its myriad &lt;code&gt;String&lt;/code&gt;/&lt;code&gt;&amp;amp;str&lt;/code&gt;/&lt;code&gt;OsString&lt;/code&gt;/&lt;code&gt;&amp;amp;osstr&lt;/code&gt; and goodness knows what else types. A lot of the complexity in learning Rust comes from thinking about ownership and lifetimes which are made explicit to prevent memory issues.&lt;/p&gt;

&lt;p&gt;Largely, it feels like the comment on Lisp: learn it, and it will make you a better programmer, but you probably won't want to keep it as a main language. Not to say that there aren't Rust devs (goodness knows there are quite a few now), but for the common mortal who is not systems-programming, it is more than what is needed to get a job done.&lt;/p&gt;

&lt;p&gt;I have included quite a bit of commentary because I feel the need to explain &lt;em&gt;why&lt;/em&gt; the example isn't simpler than it is...&lt;/p&gt;

&lt;p&gt;For the top level file, write in &lt;code&gt;./src/hey.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Declare that there is a module "stuff" ...&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;stuff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Use the "hello" submodule from the declared "stuff" module&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;stuff&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_arguments&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Get the arguments from CLI and do check, then&lt;/span&gt;
    &lt;span class="c1"&gt;// return the arguments, without the program name&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.collect&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;args&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please specify arguments !"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;process&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&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="c1"&gt;// We get a slice of an existing vector&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;// but to return it, we need it to be a vector - so cast it back explicitly&lt;/span&gt;
        &lt;span class="nf"&gt;.to_vec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_arguments&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;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&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="nn"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then write a &lt;code&gt;src/stuff.rs&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This is the side-module "stuff"&lt;/span&gt;
&lt;span class="c1"&gt;// It has submodule implementations in "stuff/"&lt;/span&gt;
&lt;span class="c1"&gt;//   declare their existence here. Note that this is&lt;/span&gt;
&lt;span class="c1"&gt;//   needed even for each submodule to see each other&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then write the submodule in &lt;code&gt;src/stuff/hello.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Create a "mutable" and "owned"/heap String from the string-slice (native, on the stack)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Push the stack content from "name" into the head object "phrase"&lt;/span&gt;
    &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;phrase&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;Build it, and run it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rustc src/hey.rs

./hey Alex Jay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="lua"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Lua
&lt;/h2&gt;

&lt;p&gt;Lua is a popular tool scripting language - it's used in a variety of settings notably Roblox, the GNU Image Mainpulation Program ("GIMP"), and if I may just momentarily shill, in &lt;a href="https://www.minetest.net" rel="noopener noreferrer"&gt;Minetest&lt;/a&gt;. I used to write and maintain various mods for Minetest, and it's even fair to say I did a lot of my learning during that time... there's a lot of learning that can happen on spare time when you're also having fun 😄&lt;/p&gt;

&lt;p&gt;Any application that does embed Lua likely embeds a &lt;em&gt;specific&lt;/em&gt; reference version of it, and may add/remove library features as suits the application. For this test I installed the CLI interpreter for Lua 5.4, but any version of Lua would work though with this example.&lt;/p&gt;

&lt;p&gt;Most notably though, I bring attention to the fact that top-level symbols are global by default, and that to namespace a function, you need to declare it on an existing variable.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./hey.lua&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Executes a file , any non-local symbols enter the global space&lt;/span&gt;
&lt;span class="nb"&gt;dofile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"stuff/hello.lua"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Please supply arguments"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;os.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="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stuff_hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in &lt;code&gt;./stuff/hello.lua&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- This is a global variable that will go into the global space&lt;/span&gt;
&lt;span class="n"&gt;stuff_hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;-- This implements a method onto the stuff_hello object/table&lt;/span&gt;
&lt;span class="c1"&gt;--   for namespacing&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;stuff_hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Hello, "&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="s2"&gt;"!"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lua hey.lua Alex Jay Pat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="java"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Java
&lt;/h2&gt;

&lt;p&gt;We love to rant about how verbose Java is, but having rattled through a few of the other languages now, it should be possible to see how comparing simple "Hello World" examples does it undue disservice.&lt;/p&gt;

&lt;p&gt;Yet there are still some funky constraints. All files should be in a top-level package directory, and your current working directory should be its parent. Every file contains a public class, and each public class must be in a file with an exact corresponding name.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;helloyall/Hey.java&lt;/code&gt; write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;helloyall&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;helloyall.stuff.Hello&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;


&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hey&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Actual arguments start from zero - program name is&lt;/span&gt;
        &lt;span class="c1"&gt;//   not stored in the args array&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please supply arguments"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&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="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&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="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;greeter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&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="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in &lt;code&gt;helloyall/stuff/Hello.java&lt;/code&gt; write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;helloyall.stuff&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# So that java knows where to import from, CLASSPATH needs to also include local project directory&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLASSPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;".;&lt;/span&gt;&lt;span class="nv"&gt;$CLASSPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Compile&lt;/span&gt;
javac helloyall/Hey.java

&lt;span class="c"&gt;# Run - uses package notation&lt;/span&gt;
java helloyall.Hey Jay Alex Sam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="groovy"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Groovy for Jenkinsfile
&lt;/h2&gt;

&lt;p&gt;This is one that stumped me for ages - I had a right rant at Jenkinsfile Groovy a few years back for just how hard it was to find decent concise information about it.&lt;/p&gt;

&lt;p&gt;Groovy is a language designed to be a "scripting language" that runs on the JVM, which means some of its &lt;em&gt;actual&lt;/em&gt; representations are heavily influenced by Java's &lt;del&gt;limitations&lt;/del&gt; requirements.&lt;/p&gt;

&lt;p&gt;One of the key concepts to retain first is that the top level Jenkinsfile code itself runs on the server. A bad Jenkinsfile can crash a Jenkins server, so don't let just anyone write Jenkinsfile code to run on your server. note then that any SCM checkout &lt;em&gt;should&lt;/em&gt; always be done on a &lt;em&gt;node&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Another corollary to this is that each statement is passed on from the main server to the node for execution - as in, the main server steps through the Jenkinsfile, and dispatches steps individually over to the execution node. As a corollary to this corollary (get comfortable with deep-nesting in Groovy!), the &lt;code&gt;for&lt;/code&gt; and &lt;code&gt;while&lt;/code&gt; loops are forbidden, in favour of iterators.&lt;/p&gt;

&lt;p&gt;A second key concept is to know that &lt;em&gt;every Groovy script is a class with instance methods&lt;/em&gt;. This has some very interesting effects &lt;a href="https://dev.to/taikedz/gruelling-groovy-gotchas-loops-closures-and-jenkins-dsls-9pe"&gt;which I have touched on before&lt;/a&gt; and if you are about to embark on such a journey, may I humbly suggest you read those notes. They are to be essential to getting your head around some oddities you will surely encounter.&lt;/p&gt;

&lt;p&gt;Declare your main jenkinsfile at the root of your repo, write &lt;code&gt;./hey.Jenkinsfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"runner-node"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// "runner-node" should be an agent or label defined on your Jenkins server&lt;/span&gt;
    &lt;span class="c1"&gt;// Try to always confine code to a node that is _not_ your master node.&lt;/span&gt;

    &lt;span class="c1"&gt;// The hey.Jenkinsfile should be in a git repo !! Or SCM of your choice&lt;/span&gt;
    &lt;span class="c1"&gt;// The files must be checked out to a node workspace first&lt;/span&gt;
    &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="n"&gt;scm&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// We can load from the workspace, assuming your files are at the root of the repo&lt;/span&gt;
    &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="s2"&gt;"${env.WORKSPACE}/stuff/hello.groovy"&lt;/span&gt;

    &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NAMES&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;","&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Iteration - not a loop ! - with a closure&lt;/span&gt;
    &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;each&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the root of your repo, write &lt;code&gt;stuff/hello.groovy&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Hello, ${name.trim()}!"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The whole file gets encapsulated to a class&lt;/span&gt;
&lt;span class="c1"&gt;// and any "naked code" goes into a static run() method of the class.&lt;/span&gt;
&lt;span class="c1"&gt;// We must `return this;` so that the `load` operation receives the loaded instance.&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit this code and push it. On Jenkins, create a Pipeline job, and point it appropriately to your script. Make it configurable, and give it a String parameter, into which to place names. Save and choose to "Build with parameters" - you can enter the names now, like &lt;code&gt;Alex, Jay, Sam&lt;/code&gt; and see the result on the console output.&lt;/p&gt;

&lt;p&gt;&lt;a id="perl"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Perl
&lt;/h2&gt;

&lt;p&gt;My search for how to do this turned out to be unexpectedly infuriating. Some many years ago, I did do a job which involved integrating our Perl solution with customer environments, and I do not remember it being this maddening...&lt;/p&gt;

&lt;p&gt;Searching the web, I get a bunch of results as usual for using &lt;em&gt;other peoples'&lt;/em&gt; modules, but nothing for organising my own code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/3850393/how-do-i-use-perls-import-use-require-and-do" rel="noopener noreferrer"&gt;StackOverflow tells me to RTFM&lt;/a&gt;, but &lt;a href="https://perldoc.perl.org/functions/use" rel="noopener noreferrer"&gt;the FM&lt;/a&gt; is so jargonic that it might as well be an implementation spec for the feature itself rather than a user manual. An &lt;a href="https://perlmaven.com/import" rel="noopener noreferrer"&gt;attempted answer&lt;/a&gt; simply doesn't seem to work, bailing with &lt;code&gt;Can't locate A/Calc.pm in @INC&lt;/code&gt; , and same with a simpler answer on &lt;a href="https://stackoverflow.com/questions/10196634/importing-a-pl-file#10197114" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt; . It pointed also to &lt;a href="https://perldoc.perl.org/perlmod" rel="noopener noreferrer"&gt;more documentation perlmod&lt;/a&gt;. Some blogger AlivnA &lt;a href="https://alvinalexander.com/perl/edu/articles/pl010015/" rel="noopener noreferrer"&gt;gives a pointer&lt;/a&gt; which helps get past the &lt;code&gt;@INC&lt;/code&gt; issue, but the subroutine still doesn't seem to export, and at this point I've given up.&lt;/p&gt;

&lt;p&gt;This is just a sample of the hair-pulling confusion trying to hunt down how to import a file from a subfolder. I begin to suspect that this even even possible/a done thing... Perlists, please prove me wrong, I beg of you...&lt;/p&gt;

&lt;p&gt;EDIT: The gods have answered, or at least, my friend @pozorvlak took pity on my plight and &lt;a href="https://github.com/pozorvlak/perl_import" rel="noopener noreferrer"&gt;put together a working Hello Y'All Perl example&lt;/a&gt; . The incantations give rise.&lt;/p&gt;

&lt;p&gt;I ended up with this 🛑 &lt;em&gt;non working&lt;/em&gt; code.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./hey.pl&lt;/code&gt; I have&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Add to @INC list&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;lib&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./stuff&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

&lt;span class="c1"&gt;# Import from anywhere in the @INC list&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Results in "undefined subroutine &amp;amp;hello::greet"&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$phrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;hello::&lt;/span&gt;&lt;span class="nv"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;Jay&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;$phrase&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in &lt;code&gt;./stuff/hello.pm&lt;/code&gt; I have&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;stuff::&lt;/span&gt;&lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&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="s2"&gt;Howdy, &lt;/span&gt;&lt;span class="si"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;!&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I run with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;perl hey.pl

&lt;span class="c"&gt;# Undefined subroutine &amp;amp;hello::greet called at hey.pl line 4.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How is it so difficult to do this supposedly extremely commonplace activity when &lt;a href="https://www.mcmillen.dev/sigbovik/" rel="noopener noreferrer"&gt;the OCR of splattered paint&lt;/a&gt; resolves to runnable perl 93% of the time ???&lt;/p&gt;

&lt;p&gt;&lt;a id="bash-builder"&gt;&lt;/a&gt;🔝&lt;/p&gt;

&lt;h2&gt;
  
  
  Bash for &lt;a href="https://github.com/taikedz/bash-builder" rel="noopener noreferrer"&gt;Bash Builder&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If you'll indulge me, I've kept this one til last. I wrote this tool during a time I had shell scripting as my main language, being more sysadmin-oriented. One thing I wanted was to be able to write various scripts, but with re-usable code, instead of copy-pasting it around.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;source&lt;/code&gt;-ing code is unreliable - it depends on the user's current working directory, and sourced files do not have the benefit of knowing where they themselves are - &lt;code&gt;$0&lt;/code&gt; only ever hints to the &lt;em&gt;top level&lt;/em&gt; script's location. It was important to be able to perform imports from known absolute locations.&lt;/p&gt;

&lt;p&gt;As such, exporting &lt;code&gt;BBPATH=/path/to/bash/libs&lt;/code&gt; is important, and taken care of by the installer into the &lt;code&gt;~/.bashrc&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;With that done, write a &lt;code&gt;./hey.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# The out.sh lib allows doing colourful output&lt;/span&gt;
&lt;span class="c"&gt;#%include std/out.sh&lt;/span&gt;

&lt;span class="c"&gt;#%include ./stuff/hello.sh&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;out:error &lt;span class="s2"&gt;"No argument set"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Did you know that ":" is a legitimate character for a bash function name?&lt;/span&gt;
&lt;span class="c"&gt;# Any character that can be a file character can be used.&lt;/span&gt;
&lt;span class="c"&gt;# Used here for namespacing.&lt;/span&gt;
&lt;span class="nv"&gt;phrase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;hello:greet &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
out:info &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$phrase&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And also write a &lt;code&gt;./stuff/hello.sh&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Bash-Builder provides some syntax sugar macros for putting names on&lt;/span&gt;
&lt;span class="c"&gt;#  positional arguments. The rest remain in the "$@" array variable&lt;/span&gt;
&lt;span class="nv"&gt;$%&lt;/span&gt;&lt;span class="k"&gt;function &lt;/span&gt;hello:greet&lt;span class="o"&gt;(&lt;/span&gt;name&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build it and run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bbuild hey.sh bin/hey

bash bin/hey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that even this works, due to the imports being resolved at build time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;stuff
bash ../bin/hey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing directory and calling like that &lt;em&gt;does not&lt;/em&gt; work with regular bash sourcing. Sourcing was one of the major issues I had started developing &lt;code&gt;bash-builder&lt;/code&gt; to solve. Once I had the macros for the inclusion work, it was only a small step to include the syntactic sugar macros of &lt;code&gt;%function(name1 name2 ...)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Arguably, a lot of the richness comes from its associated project &lt;code&gt;bash-libs&lt;/code&gt; which provides a sort of standard library for extra goodiness ...&lt;/p&gt;

&lt;p&gt;&lt;a id="conclusion"&gt;&lt;/a&gt;🔝&lt;/p&gt;

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

&lt;p&gt;There we are. A whirlwind tour of a dozen languages demonstrating a Hello-World that's a bit more useful than the basic.&lt;/p&gt;

&lt;p&gt;If you write language documentation and tutorials, I hope this inspires you to put something like this in the introduction or first chapter, to give a better flavour of the language.&lt;/p&gt;

&lt;p&gt;Any popular languages not on this list ? What does your list of languages look like implementing "Hello Y'All"&lt;/p&gt;

</description>
      <category>helloworld</category>
      <category>helloyall</category>
      <category>programming</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Baby steps with Go</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Fri, 02 Aug 2024 14:49:06 +0000</pubDate>
      <link>https://dev.to/taikedz/baby-steps-with-go-3ibl</link>
      <guid>https://dev.to/taikedz/baby-steps-with-go-3ibl</guid>
      <description>&lt;p&gt;&lt;a href="https://www.flickr.com/photos/ducakedhare/53553698094/" rel="noopener noreferrer"&gt;Image (C) Tai Kedzierski&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I decided to give Go a try on my journey to pick up a new language that would be useful to my career and interests. This time I've been having a go at Go. I think as first impressions go, it's pretty nice.&lt;/p&gt;

&lt;p&gt;This is not a guided tour, and arguably, not written for anyone else other than myself, as some personal reminders.&lt;/p&gt;

&lt;p&gt;I gave myself a small project for it called &lt;a href="https://github.com/taikedz/os-release-q" rel="noopener noreferrer"&gt;Os-Release-Q&lt;/a&gt; . My intention was to be able to have a binary on any system I manage, such that I can print out exactly the information I need, without needing to parse or eye-grep for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  First hurdle : &lt;code&gt;import&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Searching the web talks a lot about importing other people's packages , but very little about organising one's own code. Even the docs focus on &lt;code&gt;go get&lt;/code&gt; rather than separation of concerns.&lt;/p&gt;

&lt;p&gt;I encounter this hurdle quite a bit in every language, as each has its own idiosyncratic philosophy on how to go about it, and what limitations each has or imposes. (I wrote &lt;a href="https://dev.to/taikedz/polydev-a-better-hello-world-for-polyglot-devs-37p2"&gt;a piece on this&lt;/a&gt; as a direct follow-up to learning Go's import idisyncracies)&lt;/p&gt;

&lt;p&gt;Of all the activities I undertook in learning the basics, coming from a predominantly python background, splitting my code into multiple files was what took me the longest to get answers to. In summary, I found the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;top level needs a &lt;code&gt;go.mod&lt;/code&gt; declaring &lt;code&gt;module module-name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;I can then set a &lt;code&gt;src/&lt;/code&gt; directory at top level, and a &lt;code&gt;src/main.go&lt;/code&gt; in which to place my main function , with a &lt;code&gt;package main&lt;/code&gt; declaration at the top&lt;/li&gt;
&lt;li&gt;putting code in other files is a simple as creating a file like &lt;code&gt;src/others.go&lt;/code&gt; with a &lt;code&gt;package main&lt;/code&gt; declaration.&lt;/li&gt;
&lt;li&gt;All functions and variables become available directly in any other file of &lt;code&gt;package main&lt;/code&gt; , but the files need to be &lt;em&gt;explicitly&lt;/em&gt; stated on the &lt;code&gt;go build FILES&lt;/code&gt; call - e.g. &lt;code&gt;go build src/main.go src/others.go&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For local submodules, the submodule must reside in a folder. It can declare a &lt;code&gt;package submodule-name&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Say it is in &lt;code&gt;src/submod/&lt;/code&gt;, with main implementor in &lt;code&gt;src/submod/submod.go&lt;/code&gt;. In &lt;code&gt;main.go&lt;/code&gt; we do &lt;code&gt;import "module-name/src/submod"&lt;/code&gt; (with &lt;code&gt;module-name&lt;/code&gt; pulled from &lt;code&gt;go.mod&lt;/code&gt;). And then we can call &lt;code&gt;submod.SomeFunction()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We note that submodule functions are only available to importers if their name starts with a Capitalised letter. So no doing &lt;code&gt;submod.myFunction()&lt;/code&gt; - it has to be &lt;code&gt;submod.MyFunction()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are surely other considerations around submodules and imports, but as far as keeping code organised and segregated, this is the essentials.&lt;/p&gt;

&lt;p&gt;To keep things sane, I tempted to only have one file declaring &lt;code&gt;package main&lt;/code&gt;, and isolating the rest into submodules - these get imported automatically without needing to be declared in the &lt;code&gt;go build FILES&lt;/code&gt; list of files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doing basic tasks
&lt;/h2&gt;

&lt;p&gt;After I had resolved this specificity of Go, the rest fell in to place quite easily. For every basic task there was of course a StackOverflow entry, or a GoByExample.com page, and more basically, the Go language reference.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;String handling is done via the &lt;code&gt;strings&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;Array handling has a number of native functions, of which the &lt;code&gt;base_array = append(base_array, item1, item2)&lt;/code&gt; pattern - it also works for extending an array with the values of another via &lt;code&gt;append(base, other_array...)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Error handling is done by passing out error objects typically, but not necessarily.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;"log"&lt;/code&gt; lib exists for a handy pre-configured no-faffing log. It includes a &lt;code&gt;log.Fatal(message)&lt;/code&gt; call which logs an error, as well as immediately exiting.&lt;/li&gt;
&lt;li&gt;Calling subprocesses is easy via the &lt;code&gt;"os/exec"&lt;/code&gt; library, using &lt;code&gt;exec.Command(base, args...)&lt;/code&gt; pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compile-time errors were by and large intuitive, based on a basic understanding of the language (it's not the first time I looked at it, and on the sruface, it's a very simple and straightforward syntax)&lt;/p&gt;

&lt;p&gt;Two particularly common tasks deserve their own paragraphs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error handling
&lt;/h2&gt;

&lt;p&gt;Basic error handling is often commented as being cumbersome, literally needing to handle errors in the midst of control flow. This may be anathema to programmers coming from a try/catch workflow, but handling the issue at the point where it can happen isn't so bad.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// explicit return item `err` forces us to be aware of it&lt;/span&gt;
&lt;span class="c"&gt;// but having the ability to check it in the same breath is not so bad&lt;/span&gt;
&lt;span class="k"&gt;if&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;someCall&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sorry."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare try/catch way&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&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="nf"&gt;someCall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print_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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sorry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;I've seen hintings at people being unhappy with the whole "got to check err in the middle of my code" which certainly removes the ability to group-handle errors. For example in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;do_thing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;and_more&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;and_other&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ErrType&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;ErrType&lt;/code&gt; is in fact thrown by all three , this is a handy way to catch each scenario. In Go, it's a little bit more cumbersome&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;do_all_the_things&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;do_thing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;and_more&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&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;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;and_other&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt;

&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;do_all_the_things&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sorry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is very much predicated on long sequences of calls wanting to be grouped under a same error handling routine, and how much that actually happens to people I cannot say. I guess I'll find out in my own time, but I remain, for now, unfazed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Argument Parsing
&lt;/h2&gt;

&lt;p&gt;I can't help but feel that the implementation of the &lt;code&gt;flags&lt;/code&gt; library is a bit half-baked. Evidently people are used to and OK with it, given its survival in its current form.&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;program -flag arg1 arg2&lt;/code&gt; gives us the toggle that &lt;code&gt;flag&lt;/code&gt; is set up to do, and &lt;code&gt;positionals := flags.Args()&lt;/code&gt; returns us the array of &lt;code&gt;["arg1", "arg2"]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However calling &lt;code&gt;program arg1 arg2 -flag&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; toggle whatever &lt;code&gt;-flags&lt;/code&gt; is supposed to do, and instead gives is &lt;code&gt;positionals&lt;/code&gt; as &lt;code&gt;["arg1", "arg2", "-flag"]&lt;/code&gt; wherein the flag was not parsed.&lt;/p&gt;

&lt;p&gt;This may be useful for passing in a sub-call like &lt;code&gt;program colorize ls -l&lt;/code&gt; where the &lt;code&gt;ls -l&lt;/code&gt; is passed down literally - so I can see a use case.&lt;/p&gt;

&lt;p&gt;It's just that most programs out there allow flag arguments anywhere around positional items. &lt;code&gt;ls dir1/ -l dir2/&lt;/code&gt; is the same as &lt;code&gt;ls -l dir1/ dir2/&lt;/code&gt;, and this is a convention that holds on the vast majority of Unix and Linux commands.&lt;/p&gt;

&lt;p&gt;It may be just that this is something to get used to - and worth calling out.&lt;/p&gt;

&lt;p&gt;EDIT: In the end, I implemented &lt;a href="https://github.com/taikedz/GoArgs" rel="noopener noreferrer"&gt;a parsing lib of my own&lt;/a&gt; with the niceties that I desired&lt;/p&gt;

&lt;h2&gt;
  
  
  Purpose and use case of Go
&lt;/h2&gt;

&lt;p&gt;The file import paradigm aside, I found it pretty easy to get my basic application implemented. Anything I did wrong felt fairly obvious and the errors were meaningful. It really does feel like I can just focus on "getting things done."&lt;/p&gt;

&lt;p&gt;From my very meagre amount of use so far, and taking my specific needs into account, I can see the following advantages&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;easy to get started&lt;/li&gt;
&lt;li&gt;compiled binary, no runtime dependency&lt;/li&gt;
&lt;li&gt;simple language with types is a step up from shell scripting&lt;/li&gt;
&lt;li&gt;allegedly easy multiprocessing support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I thought having sparse types instead of objects and inheritance would be a hinderance, but so far so good. I get by without them in other languages, so I suppose when I do get around to defining interfaces and types, it will feel like a step up from Lua and bash. I hope.&lt;/p&gt;

&lt;p&gt;One of the reasons I wanted to explore a compiled-to-native language was to be able to produce binaries that could easily be shunted around, without needing to rely on a particular version of a runtime being present.&lt;/p&gt;

&lt;p&gt;A colleague once walked up to my desk in dismay, trying to solve getting Java 17 onto an old Node base image which was based on Debian 10 . Either he'd have to upgrade the Node version to get a newer base image, use a new Debian base image and install and configure Node manually, or scour the internet for a custom repo hosted by goodness-knows-who for a goodness-knows-if-hacked Java 17 that would run on Debian 10. Each solution would have ended up entailing further refactoring of the code base.&lt;/p&gt;

&lt;p&gt;How much easier if the deployed software had no such conflicting runtime dependencies...&lt;/p&gt;

&lt;p&gt;From an ops point of view, the one big gain I am feeling I would stand to feel is: I can easily write code, and build an ELF binary to then deploy on "arbitrary system X" and not have to contend with ensuring the right version of a given runtime is in place, and managing conflicting dependencies.&lt;/p&gt;

&lt;p&gt;I've seen it touted before as an alternative glue language to replace shell scripting, and I can &lt;em&gt;just about&lt;/em&gt; see that. One of the big advantages of shell scripting is the ability to pipe outputs from one command directly into another - but most often, the things that sit in that pipe are &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt; and other text-massaging utilities. These can be replaced by language-native functions, and my basic experience here with getting output from a command has been pretty good. The only impediment in &lt;em&gt;this&lt;/em&gt; scenario is that the Go program needs to be compiled whereas the shell can just run. It really will depend on what the deployment requirements are, but as soon as "runtime dependency" kicks in, I would be fairly tempted to reach for Go.&lt;/p&gt;

&lt;p&gt;I'm sure there are other benefits, and I have heard a great deal said about the ease of use of multithreading and multiprocessing in Go, and I do intend on cooking up a mini project to explore that as a next step - probably something that might listen for inputs on multiple channels, and perform some basic tasks in response. I have had a use-case for that in some test automation tasks I've had before, so it's not alien to me at this point.&lt;/p&gt;

</description>
      <category>go</category>
      <category>learning</category>
      <category>devjourney</category>
    </item>
    <item>
      <title>Rust's Option type... in Python</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Fri, 13 Oct 2023 14:14:18 +0000</pubDate>
      <link>https://dev.to/taikedz/rusts-option-type-in-python-547p</link>
      <guid>https://dev.to/taikedz/rusts-option-type-in-python-547p</guid>
      <description>&lt;p&gt;&lt;small&gt;&lt;a href="https://www.flickr.com/photos/ducakedhare/5975823310/" rel="noopener noreferrer"&gt;Cover Image (C) Tai Kedzierski&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;How many times have you written/seen code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks reasonable right?&lt;/p&gt;

&lt;p&gt;How about if &lt;code&gt;data == None&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;It is so easy to assume &lt;em&gt;thingness&lt;/em&gt; and forget to handle &lt;em&gt;nullness&lt;/em&gt;. So frequent. In Python, Java, JavaScript, and many other languages, this is prone to happening.&lt;/p&gt;

&lt;p&gt;Then some languages, like Rust, have a semantic way of dealing with this... and I pondered, what if we tried to intorduce this to Python? How would it look?&lt;/p&gt;

&lt;p&gt;Just for a laugh, and in between waiting for integration tests to finish running, I threw this together: &lt;a href="https://gist.github.com/taikedz/44e3af7d30d124f10974ca45f9780021" rel="noopener noreferrer"&gt;a quick Python implementation to mimic Rust's &lt;code&gt;Option&lt;/code&gt; type&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Rust, the &lt;code&gt;Option&lt;/code&gt; enumeration type is used with the &lt;code&gt;match&lt;/code&gt; operator to force handling the concept of null-ness, without treating it as a first-order value, unlike in languages that have a null representation.&lt;/p&gt;

&lt;p&gt;Does that sound weird? Let me digress a moment&lt;/p&gt;

&lt;h2&gt;
  
  
  Nullity as a typed value, not a stand-in
&lt;/h2&gt;

&lt;p&gt;In languages where there can be a &lt;code&gt;None&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt; &lt;em&gt;placeholder&lt;/em&gt;-concept, it works like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;functionA()&lt;/code&gt; returns a value, say of &lt;em&gt;type&lt;/em&gt; &lt;code&gt;String&lt;/code&gt; (or other, it is immaterial). If &lt;code&gt;functionA()&lt;/code&gt; returns &lt;code&gt;null&lt;/code&gt;, it effectively says it returned &lt;code&gt;null&lt;/code&gt; &lt;em&gt;instead of&lt;/em&gt; a String. Trying to treat this &lt;code&gt;null&lt;/code&gt; as String (by calling its methods, concatenating it, etc) leads to errors.&lt;/p&gt;

&lt;p&gt;In Rust, this cannot happen.&lt;/p&gt;

&lt;p&gt;In Rust if &lt;code&gt;functionA()&lt;/code&gt; says returns a String, it &lt;em&gt;always returns a valid string&lt;/em&gt;. If we want to express that a non-valid value can be returned, then &lt;code&gt;functionA()&lt;/code&gt; must flip: it returns an &lt;code&gt;Option&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;We must then handle the &lt;code&gt;Option&lt;/code&gt; enumeration type - check if it is the variant known as &lt;code&gt;None&lt;/code&gt; , or check if it is the variant known as &lt;code&gt;Some&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can then &lt;code&gt;.unwrap()&lt;/code&gt; the result explicitly, or through pattern matching implicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cs"&gt;# Panics if we get a None variant&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;functionA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cs"&gt;# vs&lt;/span&gt;

&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;functionA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fail!"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Success: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  In Python
&lt;/h2&gt;

&lt;p&gt;So how does this experiment look in Python ?&lt;/p&gt;

&lt;p&gt;Well, we're not replacing the native &lt;code&gt;None&lt;/code&gt; type. We'll use a &lt;code&gt;Null&lt;/code&gt; class (a regular class), subclassed to &lt;code&gt;Option&lt;/code&gt;. I didn't include a &lt;code&gt;Some&lt;/code&gt; type, but it would be simple enough - just &lt;code&gt;class Some(Option): pass&lt;/code&gt; and it's done. Everything is in fact implemented on &lt;code&gt;Option&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We are then able to wrap this around any return result we care to add to our script to make it return an &lt;code&gt;Option&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;some_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="c1"&gt;# ... implementation ...
&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;not_valid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Explicit null-return
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Null&lt;/span&gt;

    &lt;span class="c1"&gt;# or even
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# (will behave like Null if some_value is still None)
&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;some_func&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;# handle it
&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This forces whoever uses &lt;code&gt;some_function()&lt;/code&gt; to consider that nullity can come of it, before gaining access to the value itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Without a check, this may "panic" (borrowing from rust's terminology)
#  the program exits systematically with an error message
&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;some_func&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed to get data from some_func&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# On occurrence of nullity, a default value is substituted instead.
&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;some_func&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;or_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes for explicit force-handling of &lt;code&gt;None&lt;/code&gt; , where before it could easily pass under the review radar silently.&lt;/p&gt;

&lt;p&gt;An interesting side-effect is that managing default-substitution is now done outside of &lt;code&gt;some_func&lt;/code&gt;'s logic; the design of &lt;code&gt;some_func&lt;/code&gt; can stay unencumbered with specifically dealing with alternate eventualities, just as the caller code can declare the default value without multiple lines of if/else checking.&lt;/p&gt;

&lt;p&gt;We also don't have a &lt;code&gt;match&lt;/code&gt; keyword to use, but this doesn't impede the usability in any significant way - merely having to acknowledge unwrapping brings gains, and the &lt;code&gt;or_raise()&lt;/code&gt; method allows some additional flow control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should this even be used in Python ?
&lt;/h2&gt;

&lt;p&gt;I am actually tempted to use it in my projects... as a way of forcing awareness of null possibility.&lt;/p&gt;

&lt;p&gt;It ensures that nullness cannot be ignored/forgotten by the caller, promoting more conscientious coding, and helping avoid some common pitfalls.&lt;/p&gt;

&lt;p&gt;It is succinct enough to allow minimal changes in code flow, but explicit so that it cannot be ignored.&lt;/p&gt;

&lt;p&gt;But it's very un-idiomatic, literally "trying to write Rust style code in Python."&lt;/p&gt;

&lt;p&gt;And yet.&lt;/p&gt;

&lt;p&gt;🪙 A penny for you thoughts?&lt;/p&gt;

</description>
      <category>rust</category>
      <category>python</category>
      <category>discuss</category>
      <category>null</category>
    </item>
    <item>
      <title>Over to Rust - Gotchas for Beginners</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Sun, 10 Sep 2023 16:38:42 +0000</pubDate>
      <link>https://dev.to/taikedz/from-python-to-rust-notes-from-a-simple-rust-starter-project-3362</link>
      <guid>https://dev.to/taikedz/from-python-to-rust-notes-from-a-simple-rust-starter-project-3362</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover image &lt;a href="https://flickr.com/photos/ducakedhare/52917260497/" rel="noopener noreferrer"&gt;(C) Tai Kedzierski&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;I had an idea for a simple utility the other day - a way to manage a *nix &lt;code&gt;$PATH&lt;/code&gt;. At it's core, it has one file reading operation, which also does some line filtering, and one file-append operation. That's all.&lt;/p&gt;

&lt;p&gt;I wrote it up quickly in python and &lt;a href="https://gist.github.com/taikedz/4cda9e4650ad10fe827c1224816e0269" rel="noopener noreferrer"&gt;threw it into a Github gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I then realised, hey, this program is pretty simple. I wonder how easy it would be to write it in rust? And so the journey began...&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust-lust
&lt;/h2&gt;

&lt;p&gt;What is Rust? Articles abound on the Net and this site. Suffice to say it is a new language that has attracted the envy of many - &lt;a href="https://stackoverflow.blog/2020/01/20/what-is-rust-and-why-is-it-so-popular/" rel="noopener noreferrer"&gt;StackOverflow blog posted some thoughts in 2020&lt;/a&gt;, and &lt;a href="https://survey.stackoverflow.co/2023/#section-admired-and-desired-programming-scripting-and-markup-languages" rel="noopener noreferrer"&gt;in the 2023 developer survey&lt;/a&gt;, over 80% of respondents who have used it in the past year want to keep on using it.&lt;/p&gt;

&lt;p&gt;I've been wanting to properly sit down and learn rust for a while now - at least a couple of years. I mainly work with python, which is a superb language for getting things done fast - but that low barrier to entry encourages one undesirable thing: messy, buggy code. Its surge in popularity has been attributed plenty of times to it being easy to learn, the dynamic-typing and very forgiving runtime allow you to see results in minutes, sometimes even seconds, but at the cost of letting you get away with code-murder.&lt;/p&gt;

&lt;p&gt;I really want to learn rust not only for its speed and memory safety (I am perennially eyeing up the goal of writing a multiplayer game server), but also to benefit from thinking about code fundamentally differently, and open up new practices to apply further afield.&lt;/p&gt;

&lt;p&gt;The learning curve is proving to be not so gentle of course, but its advertised advantages feel worth it. But as all things in learning, you need some practical exercising to properly internalise the lesson.&lt;/p&gt;

&lt;p&gt;Some resource I had been following suggested first reading through &lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;The Book&lt;/a&gt; without typing any code, and then re-visit the book again after ingesting the basics with a more holistic idea. I had already done that first part (I couldn't help myself, I was experimenting as I went along), and was now itching for an actual project. The Book provides some useful mini-projects to try out by way of a practical tutorial, but what I really wanted was something &lt;em&gt;I would find useful myself&lt;/em&gt;. &lt;code&gt;pathctl&lt;/code&gt; was just what I needed. There were a few very simple requirements, and I had proven its simplicity by doing it in a language I know.&lt;/p&gt;

&lt;p&gt;After an initial fortnight of dipping into The Book, it has taken me one week (first python on Monday, basic completion of rust project on Sunday).&lt;/p&gt;

&lt;p&gt;Here's some notes from my mini-journey so far - things that The Book didn't cover quite so obviously, or where I was just thrown as a python/dynamic/other-language programmer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ownership and the Borrow Checker
&lt;/h2&gt;

&lt;p&gt;I was exposed to some C programming many years ago at university, and I remember distinctly disliking having to juggle heap pointers and manage memory de/allocations. They're not a difficult concept to grasp at all, but managing the wee blighters is a chore - testament to which the numerous dereference bugs, and the very existence of rust.&lt;/p&gt;

&lt;p&gt;Rust's Ownership concept and the compile-time Borrow Checker feel jarring to work with at first, especially coming from a dynamic language, but its novelty fades away very quickly into a level of semi-comfort.&lt;/p&gt;

&lt;p&gt;Operations on Strings usually return &lt;code&gt;&amp;amp;str&lt;/code&gt; slices , which are references to the original data - owned. So if you have a vector (&lt;code&gt;list&lt;/code&gt; for the pythonistas out there) of items, and you want to return a vector of modified strings, you need to explicitly convert these to new objects. This might seem memory-inefficient at first, but that's in fact what pretty mcuh &lt;em&gt;any&lt;/em&gt; language will do under the hood. It's just explicit in rust:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;load_valid_lines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The actual file opening/reading etc is done elsewhere&lt;/span&gt;
    &lt;span class="nf"&gt;read_lines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Explicitly iterate&lt;/span&gt;

        &lt;span class="c1"&gt;// trim() returns a &amp;amp;str , referencing the iterated line&lt;/span&gt;
        &lt;span class="c1"&gt;// which cannot be returned (owned and remaining in the function)&lt;/span&gt;
        &lt;span class="c1"&gt;// so we produce a new String using a one-line closure&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

        &lt;span class="c1"&gt;// the `is_valid_line()` function checks the item without taking ownership: pass in `&amp;amp;line`&lt;/span&gt;
        &lt;span class="nf"&gt;.filter&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;is_valid_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="c1"&gt;// and finally create a vector, from the map .&lt;/span&gt;
        &lt;span class="c1"&gt;// Note the "::" and the doubled '&amp;lt;' for generic-in-generic&lt;/span&gt;
        &lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enums
&lt;/h2&gt;

&lt;p&gt;In the two languages I had previously looked at for enums, &lt;a href="https://docs.python.org/3/library/enum.html" rel="noopener noreferrer"&gt;python&lt;/a&gt; and &lt;a href="https://www.w3schools.com/java/java_enums.asp" rel="noopener noreferrer"&gt;Java&lt;/a&gt;, their enum types were both cemented collections of &lt;em&gt;values&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Rust does it a bit differently - additionally to being a list of fxied values, &lt;a href="https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html" rel="noopener noreferrer"&gt;enums can also encode&lt;/a&gt; for a simple &lt;em&gt;type family&lt;/em&gt; using value tuples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;IPAddress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;IPv4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;IPv6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IPAddress&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;IPv4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also means that Enums can have shared implementation functions ... and perhaps some more.&lt;/p&gt;

&lt;p&gt;I gave up on using Enums for my argument action logic, because I got myself into a bit of a tizzy in trying to use them.&lt;/p&gt;

&lt;p&gt;One use-case of Enums however ties in with the &lt;code&gt;match&lt;/code&gt; mechanism, native to the language, which allows thinking of returned values as being of particular distinct eventualites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Result&lt;/code&gt; Enum expresses the idea that an operation could have succeeded or failed, and forces the caller to handle both&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Options&lt;/code&gt; Enum expresses the idea that an operation could have produced &lt;code&gt;Some(T)&lt;/code&gt; result, or &lt;code&gt;None&lt;/code&gt; (an eventuality if you will, but &lt;em&gt;not a value&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  There is no &lt;code&gt;null&lt;/code&gt; only nullity.
&lt;/h2&gt;

&lt;p&gt;A special Enum &lt;code&gt;Option&lt;/code&gt; allows handling the cases of &lt;code&gt;None&lt;/code&gt; or &lt;code&gt;Some(T)&lt;/code&gt; - there is no &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt; type or value that can be passed around, but instead the &lt;code&gt;Option&lt;/code&gt; enumeration that allows expressing that eventuality, and handling it over the &lt;code&gt;match&lt;/code&gt; mechanism.&lt;/p&gt;

&lt;p&gt;Instead of being able to say "&lt;a href="https://www.youtube.com/watch?v=bx1YfQF0WNQ" rel="noopener noreferrer"&gt;I've got nothing&lt;/a&gt;", with ambiguity over whether &lt;em&gt;NothingTM&lt;/em&gt; might be actually a new brand of egregiously air-filled popped snacks; rust forces you to conceive that "I didn't get any valid value from the operation."&lt;/p&gt;

&lt;p&gt;It's a very subtle difference, but it does introduce a deliberate idiomatic way of thinking about the concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error handling
&lt;/h2&gt;

&lt;p&gt;Error handling is also done frequently via the &lt;code&gt;match&lt;/code&gt; item on operations that return Enums. A common Enum is &lt;code&gt;Result&lt;/code&gt; which can either be &lt;code&gt;Err&lt;/code&gt; or &lt;code&gt;Ok&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You usually need to handle it with your result to get the handler you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;FileOpener&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I'm in!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oftentimes, code snippets will use &lt;code&gt;unwrap()&lt;/code&gt; on their snippets for the sake of brevity, but that removes control from you the programmer to simply panicking the process, and exposing programming guts at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Panics altogether if something goes wrong&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;file_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FileOpener&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I'm in!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So whenever there's an &lt;code&gt;unwrap()&lt;/code&gt; in the chain, it's better to split it out into a &lt;code&gt;match&lt;/code&gt; and deal with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-    read_to_string(path_str) 
-        .unwrap()           // panic on possible file-reading errors
-        .lines()            // split the string into an iterator of string slices
-        .map(String::from)  // make each slice into a string
-        .collect()          // gather them together into a vector
&lt;/span&gt;&lt;span class="gi"&gt;+    match read_to_string(path_str) {
+        Err(e) =&amp;gt; {
+            eprintln!("Error reading file '{}': {}", path_str, e);
+            std::process::exit(1);
+        }
+        Ok(data) =&amp;gt; {
+            data.lines()            // split the string into an iterator of string slices
+                .map(String::from)  // make each slice into an owned string
+                .collect()          // gather them together into a vector
+        }
+    }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  "Catching" Errors
&lt;/h3&gt;

&lt;p&gt;On that note - there are two kinds of errors to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the kind you predict can happen and have coded around&lt;/li&gt;
&lt;li&gt;the kind that you really shouldn't have let happen (panic)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(there are of course the kind you couldn't conceive of ahead of time, but we'll let that one slide)&lt;/p&gt;

&lt;p&gt;I've seen it posited that any error that you can identify in &lt;code&gt;Result&lt;/code&gt; type or by simply returning a given value can and probably should be handled. If you don't handle them (naughty use of &lt;code&gt;unwrap()&lt;/code&gt;?) and allow the program to panic as a result, it's on you. Handle them there and then, and if throwing them up a level, do so using idiomatic structures like the &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Option&lt;/code&gt; Enums.&lt;/p&gt;

&lt;p&gt;Conversely, if a program &lt;em&gt;panics&lt;/em&gt; &lt;strong&gt;don't seek to catch that&lt;/strong&gt;. Relying on the program panicking as a way of doing flow control is essentially viewed as sloppy - something you didn't care to cleanly pass values for, showing that perhaps you &lt;em&gt;didn't quite think of that&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;(Of course, if a library deep-down chooses to panic rather than return a &lt;code&gt;Result::Err&lt;/code&gt;, it's up for debate. I'm not yet conversant enough in the ecosystem to know what should be thought of with such an eventuality)&lt;/p&gt;

&lt;p&gt;The use of &lt;code&gt;try/catch&lt;/code&gt; in many languages as a control flow mechanism is seen as encouraging the programmer to see an &lt;em&gt;exceptional&lt;/em&gt; circumstance as &lt;em&gt;normal possibility&lt;/em&gt;. It might be semantics, it might simply just be idiomatic.&lt;/p&gt;

&lt;p&gt;But rust &lt;em&gt;very pointedly&lt;/em&gt; encourages the programmer handle cases properly, and see a &lt;code&gt;panic&lt;/code&gt; as a symptom of something arising from improper design.&lt;/p&gt;

&lt;p&gt;EDIT - I've been around a few more doc pages and modules, and found that my above understanding needs to be more nuanced... certainly using &lt;a href="https://doc.rust-lang.org/std/result/enum.Result.html" rel="noopener noreferrer"&gt;&lt;code&gt;.unwrap_*&lt;/code&gt; alternative functions&lt;/a&gt; can offer some level of acceptable blissful ignorance.&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;The Book&lt;/em&gt; itself, there is a section dedicated to understanding &lt;a href="https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html" rel="noopener noreferrer"&gt;when panicking should be considered suitable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It can be seen that ultimately, if there is really no sense in keeping on, it might be sensible enough to just panic.&lt;/p&gt;

&lt;p&gt;My own take however is that if you choose to panic, the only result is the aborting of the program - and often that can lead to unintended consequences. Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;collate_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ConnectionType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Create a temp file with each 'X' replaced by an arbitrary letter&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;tempfiles&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".temp-XXXX"&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;input_file&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;in_files&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;process_and_write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// panics?&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="nf"&gt;.send_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="nf"&gt;.remove&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;If you write &lt;code&gt;process_and_write&lt;/code&gt; such that it panics if the input file cannot be found (for example), not only do you skip writing the result back over the network, but you also prevent any cleanup actions.&lt;/p&gt;

&lt;p&gt;Especially, if you write a &lt;code&gt;process_and_write&lt;/code&gt; function as a library utility for others to consume, you prevent others from performing their own cleanups as needed. So as best possible, &lt;em&gt;never panic when you are writing library&lt;/em&gt;. By the same token, don't depend on library functions that panic when providing your own library.&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%2Fi.imgflip.com%2F81n57n.jpg" 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%2Fi.imgflip.com%2F81n57n.jpg" alt="Keep calm and return Result(T,E)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules and submodules
&lt;/h2&gt;

&lt;p&gt;Rust distinguishes (though I found the documentation a little light here) modules and submodules, and the programmer needs to declare them properly.&lt;/p&gt;

&lt;p&gt;Say I have a module &lt;code&gt;util.rs&lt;/code&gt; , sidecar to my &lt;code&gt;main.rs&lt;/code&gt;. Say I want my &lt;code&gt;util&lt;/code&gt; module to have two submodules, &lt;code&gt;slice.rs&lt;/code&gt; and &lt;code&gt;dice.rs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my main script, I can call&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that tells the compiler we expect a module &lt;code&gt;util.rs&lt;/code&gt; to be present (there's a legacy variation for this, but this is a simpler way for me to brain this). Inside that file, I must use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;dice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not (only) for exposing those submodules to my main file. They actually tell the compiler that those submodules are expected to exist.&lt;/p&gt;

&lt;p&gt;Even if my main file only will use &lt;code&gt;slice&lt;/code&gt; , if I want to access some functions from &lt;code&gt;dice&lt;/code&gt; , the latter &lt;em&gt;must&lt;/em&gt; be declared in the supermodule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binary sizes
&lt;/h2&gt;

&lt;p&gt;A normally &lt;code&gt;rustc&lt;/code&gt; compiled/built rust program is bundled with a load of debug symbols by default, and &lt;code&gt;hello_world&lt;/code&gt; typically clocks in a 12 MB . This is huge, given that this is supposed to be a systems language, one of the applications for which is supporting embedded systems.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;rustc -C strip=symbols mycode.rs&lt;/code&gt; removes these, paring the binary down to a much more reasonable 331 KB.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Cargo.toml&lt;/code&gt; file, this can be cemented as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[profile.dev]&lt;/span&gt;
&lt;span class="py"&gt;strip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"symbols"&lt;/span&gt;

&lt;span class="nn"&gt;[profile.release]&lt;/span&gt;
&lt;span class="py"&gt;strip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"symbols"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The systematic presence of debug symbols seems to surprise most people - I presume that in other languages, the default behaviour is to &lt;em&gt;not&lt;/em&gt; do this, and include them when the compiler is specifically requested to do so.&lt;/p&gt;

&lt;p&gt;I suspect this novel default behaviour is what allows new rust programmers to have debug information available out of the box. Removing the debug symbols amounting to explicitly "removing the training wheels", where as in the opposite case, training wheels need to be found. I dunno, just a hunch 🤷&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it easy ?
&lt;/h2&gt;

&lt;p&gt;I often hear about how "Spanish is easy to learn, Polish (etc) is difficult," and of course, that really depends on where you're starting from. If you know English, it is similar enough to Spanish that it's easy to pick up, relative to the case-declensions and non-latinate roots Polish. But to a native Czech, the complete opposite is likely to be true.&lt;/p&gt;

&lt;p&gt;So how is rust's learning curve?&lt;/p&gt;

&lt;p&gt;I can spot Python code written by a C programmer a mile off. Learning a new language in its idiomatic form will always be a challenge. Don't just try to "write like (my language X) in Rust." You won't get the benefits. With that in mind:&lt;/p&gt;

&lt;p&gt;For someone used to JavaScript or Python as their main, rust stands to be &lt;em&gt;quite involved&lt;/em&gt;. If you started your career purely mucking in with dynamically-typed, object-oriented, exception-catching languages without doing any lower-level programming introductions, it'll be quite an alien world.&lt;/p&gt;

&lt;p&gt;Strict typing, explicit heap references, strict ownership and a fussy compiler all combine to make it feel like progress in learning is &lt;em&gt;slow&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In my case, I did come to rust with some exposure, an era and an age ago, to the concepts of pointers and stack/heap memory, and other odds and ends, so I've managed to dust off the old knowledge to just about follow, but I'm not completely in my element either.&lt;/p&gt;

&lt;p&gt;For a C programmer, there are idiomatic challenges around the match/Enum techniques and perhaps others, and there are &lt;em&gt;types&lt;/em&gt;. You can't just declare everything as a pointer and call it a day.&lt;/p&gt;

&lt;p&gt;I expect in the end the ones who will have it easiest are those who work both with C and with a dynamic language on a frequent basis, going to and from each other, and comfortable with the idiosyncracies and idiomatics of each.&lt;/p&gt;

&lt;p&gt;Thankfully, it's not Haskell-levels of maddening.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>learning</category>
    </item>
    <item>
      <title>Considering Syncthing at work</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Wed, 23 Aug 2023 08:08:35 +0000</pubDate>
      <link>https://dev.to/taikedz/considering-syncthing-at-work-3pin</link>
      <guid>https://dev.to/taikedz/considering-syncthing-at-work-3pin</guid>
      <description>&lt;p&gt;&lt;small&gt;Header image (C) Tai Kedzierski&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;We had a need at work to pass large files around, to colleagues who could not get onto the VPN. It was company data, so spinning up an instance on a cloud provider was not an option. We needed something that would either go through company servers, or a peer-to-peer encrypted transfer. Enter: Syncthing.&lt;/p&gt;

&lt;p&gt;Syncthing uses end-to-end encryption to send files directly to other devices. If two devices are on the same network, the instances communicate directly with eachother. If not, they send traffic, encrypted, via a relay server (akin to a router).&lt;/p&gt;

&lt;p&gt;This solution can be useful for sending large files between workstations, when other means are unavailable.&lt;/p&gt;

&lt;p&gt;Of course, the Internet is vast, and the bits and bytes need to make a few hops before they can reach destination. It's also an external solution, so your company might have questions it would want to ask before greenlighting it.&lt;/p&gt;

&lt;p&gt;Here is my reasoning that allows me to say, "hey, &lt;em&gt;under these conditions&lt;/em&gt;, this solution is trustable."&lt;/p&gt;

&lt;h2&gt;
  
  
  Security considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Trustability of Solution
&lt;/h3&gt;

&lt;p&gt;Syncthing claims to be secure and E2E encrypted. The solution is well-known and several years old ; it is reasonable to presume it &lt;a href="https://www.cvedetails.com/vulnerability-list/vendor_id-17441/product_id-42732/Syncthing-Syncthing.html" rel="noopener noreferrer"&gt;has attracted sufficient scrutiny from the security community&lt;/a&gt; and nothing has been flagged as troublesome/buggy that still exists from a security standpoint.&lt;/p&gt;

&lt;p&gt;For most purposes, including corporate use, I would tend to be satisfied with the general status of this tool.&lt;/p&gt;

&lt;p&gt;I would not use it in a highly sensitive environment without further scrutiny, and proper approval channels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trustability of Build
&lt;/h3&gt;

&lt;p&gt;Use of syncthing in sensitive environments may need to consider how to determine whether the &lt;em&gt;build&lt;/em&gt; of the syncthing binary is untampered with.&lt;/p&gt;

&lt;p&gt;Installing from a well-known distro's default repositories provides a usually suitable level of assurance that it will abide by its security claims, and that the implementation is pristine (within the scope of the distro repo's practises).&lt;/p&gt;

&lt;p&gt;I would assert that any of the mirrors for Debian, Ubuntu, Fedora, RHEL and SuSE are suitable in this regard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trustability of Relay
&lt;/h3&gt;

&lt;p&gt;If two syncthing instances are on the same network, they will transfer data between eachother directly, without a third-party. If the two instances are on different networks, they will make use of a publicly hosted relay machine.&lt;/p&gt;

&lt;p&gt;All content being E2E encrypted, this should not be an issue whatsoever for security. This does depend on the installed copy being clean, and the caveat in "Trustability of Solution" stands.&lt;/p&gt;

&lt;p&gt;Beyond that, the relay acts much like a router - packets pass through it, fully encrypted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;(On Windows, use WSL with any of Ubuntu recent LTS, Fedora recent, openSUSE LTS, Debian recent...)&lt;/p&gt;

&lt;p&gt;The Syncthing team provide their own APT repository - instructions for adding it are on their own website: &lt;a href="https://apt.syncthing.net/" rel="noopener noreferrer"&gt;https://apt.syncthing.net/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do NOT use user-contributed repositories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ppa - there isn't an official one, use the above APT instructions&lt;/li&gt;
&lt;li&gt;snap/flatpak sources - don't do it&lt;/li&gt;
&lt;li&gt;docker images - don't do it&lt;/li&gt;
&lt;li&gt;third-party repositories - don't do it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arch AUR is to be rejected outright&lt;/strong&gt; for any privacy/security-related solution
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;syncthing &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="c"&gt;# Run it in the background&lt;/span&gt;
syncthing &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; syncthing.log 2&amp;gt;syncthing-errors.log &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Syncthing will open a browser to your &lt;code&gt;http://localhost:8384&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add a device by going to the bottom right section and "add device"&lt;/p&gt;

&lt;p&gt;Device (example): &lt;code&gt;A24RVJV-RCBOM6L-6PRUIEX-YRDRD6C-LWFFS7C-3Q2XN8G-IC5ZFWG-R2WBCQ2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can get the ID of your own device by going to top right menu: &lt;code&gt;Actions : Show ID&lt;/code&gt;. This ID can be shared with others. This allows a device to be recognised by a peer.&lt;/p&gt;

&lt;p&gt;The operator of a device can then choose to share a specific folder with another device it has recognised and registered, it will send a share request to that device. The device receiving the share request must confirm the share.&lt;/p&gt;

&lt;p&gt;With this share established, the workstation operators can use the defined sync folder to synchronise the data&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>synchronization</category>
      <category>syncthing</category>
      <category>dropbox</category>
    </item>
    <item>
      <title>What is DevOps, Really?</title>
      <dc:creator>TaiKedz</dc:creator>
      <pubDate>Tue, 22 Aug 2023 16:11:03 +0000</pubDate>
      <link>https://dev.to/taikedz/simple-pipelines-to-achieve-devops-2d3b</link>
      <guid>https://dev.to/taikedz/simple-pipelines-to-achieve-devops-2d3b</guid>
      <description>&lt;p&gt;&lt;small&gt;Header image (C) Tai Kedzierski&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;What is DevOps, really? Straight up: no tool "is" a DevOps-enabling tool, in-and-of-itself.&lt;/p&gt;

&lt;p&gt;Various buzzwords containing "DevOps tooling" and "Continuous X" have sprung into being, and whilst they are useful as conceptual terminology, reaching too soon for their corresponding marketing productizations is to leap-frog over the essential ground work of defining &lt;em&gt;what effect does it have on our practices&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;In its most abstract form, "DevOps" has been expressed as being "developers and operations working together."&lt;/p&gt;

&lt;p&gt;The term comes broadly from the web-oriented/Web 2.0/SaaS space where developers would make change to the core product code, and operations would take these in whatever form and deploy into production, following a basic workflow of production-then-deployment. Observing the resulting bottlenecks, and applying Agile principles of small, frequent iterations, the term DevOps eventually emerged to describe a practice of bringing bothe developer and operations into the activity of refining release cycles. Over the years since the coining of the term, various interpretations have arisen.&lt;/p&gt;

&lt;p&gt;A question to keep in mind whilst considering options and the below notes is to ask &lt;em&gt;why&lt;/em&gt;, or: "what are we setting out to achieve by implementing a DevOps approach?"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;faster delivery of product&lt;/li&gt;
&lt;li&gt;shorter development cycles&lt;/li&gt;
&lt;li&gt;easier maintenance of release branches&lt;/li&gt;
&lt;li&gt;more maintainable release procedures&lt;/li&gt;
&lt;li&gt;better auditability of builds (easy to identify what changes went where, and "where to get the latest X")&lt;/li&gt;
&lt;li&gt;more automation, less manual operation&lt;/li&gt;
&lt;li&gt;better synchronicity and coordination of deliverables (builds, documentation, release notes, …)&lt;/li&gt;
&lt;li&gt;... all of the above, and more ...?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(if these &lt;a href="https://en.wikipedia.org/wiki/Agile_software_development" rel="noopener noreferrer"&gt;sound familiar&lt;/a&gt;, it is &lt;a href="https://en.wikipedia.org/wiki/DevOps" rel="noopener noreferrer"&gt;no accident&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Interpretations of "DevOps" ➿
&lt;/h2&gt;

&lt;p&gt;One issue has been a focus on defining DevOps as being &lt;em&gt;a set of tools&lt;/em&gt; rather than &lt;em&gt;a way of working&lt;/em&gt;, and different organisations approach the domain differently, depending on those two ways of thinking.&lt;/p&gt;

&lt;p&gt;For the "set of tools" way of thinking, see the myriad Solutions produced to "do DevOps better."&lt;/p&gt;

&lt;p&gt;For a "way of working," this is up to the organisation to define, but ultimately boils down to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first collectively (all members on both sides) agreeing on the architecture and flow and goal, to get from "source code" to "deliverable"&lt;/li&gt;
&lt;li&gt;then deciding what tooling meets that design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As with many things in software engineering, "do one thing and do it well" is a good starting point. It is not an inviolable rule (the primary doctrine is to avoid doctrine), but there should be good reason to introduce complexity inherently into a given system.&lt;/p&gt;

&lt;p&gt;Often, when organisations start on a DevOps route, tools are invoked, installed, and setup, and things are strung together ad-hoc. Whilst this &lt;em&gt;can&lt;/em&gt; work it &lt;em&gt;usually&lt;/em&gt; causes a lot of 🍝 tight-coupling where none should exist, and multiple-self-referential 🪢 knots to weave into the codebase, making for very difficult technical debt to cement itself (mixed metaphors be pardoned).&lt;/p&gt;

&lt;h2&gt;
  
  
  Deliverables 📦
&lt;/h2&gt;

&lt;p&gt;DevOps has gained wider-spread adoption into non-web development organisations - the end deliverable being not "a deployed website," but some built binary which can then be shipped to another team or process, or indeed to a customer. "To publish" can mean any of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to push the files to a web server (original scenario)&lt;/li&gt;
&lt;li&gt;to put the final tarball in a artifact server&lt;/li&gt;
&lt;li&gt;to hand a ZIP file download URL to the manufacturing division for installation on devices.&lt;/li&gt;
&lt;li&gt;to produce a DEB or RPM ready for clients to pull&lt;/li&gt;
&lt;li&gt;to place a build output on a filesystem (ready for another process to consume)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essentially, determine: where do our pipes end? Deliver to there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dev and Ops working together
&lt;/h2&gt;

&lt;p&gt;In my view, the main aim to thinking about the problem up-front is to ensure good interfacing between teams' responsibilities, and &lt;em&gt;segregating&lt;/em&gt; the responsibilities of individual scripts/pipelines. Each script should either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;define an environment (a setup script)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the deliverable is an environment itself&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;execute a single build (a build script)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;consume source code and/or dependencies, in the context of an environment&lt;/li&gt;
&lt;li&gt;the deliverable is a build binary&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;orchestrate builds (a pipeline)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define the order of builds&lt;/li&gt;
&lt;li&gt;inform later steps of outputs of earlier steps&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This might sound like Dev and Ops are not working together - but quite to the contrary. To achieve this, they must work in good coordination. If there is not one single team, then there are at least two (usually more), with distinct capabilities and specialisations. "Working together" (in the interpretation I am musing here) means the team members can reach out to eachother across teams directly to achieve the agreed goal. The earlier statement of "first collectively agreeing" what the goal is, and what the scopes of responsibility are, is prerequisite to this.&lt;/p&gt;

&lt;p&gt;Each team should be able to operate on its own responsibilities independently for routine maintenance without affecting eachother, but both should come together to agree on a number of points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Dev needs to declare 📜  "this is how to invoke the build script in a minimal amount of commands"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;make clean &amp;amp;&amp;amp; make all&lt;/code&gt; (for example)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Dev must define 💻  "these are the environment requirements" ("needs to be a Rocky Linux 9.1 server, with &lt;code&gt;libcurses-dev&lt;/code&gt; and &lt;code&gt;lxml-dev&lt;/code&gt; libraries installed, with &lt;code&gt;gcc&lt;/code&gt;, &lt;code&gt;ninja&lt;/code&gt; and &lt;code&gt;jinja2&lt;/code&gt; tool chains")&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Ops needs to supply the ​🌉  infrastructure and pipelines on which to execute the build and delivery mechanisms&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Ops needs to provide any ​📚  other outputs (like build logs, test reports, etc) as corollary deliverables, through desired channels - package repos, etc - and advise how to access these&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Ops may also be directed to integrate ​🔀 other operations to the pipeline - running tests written by automation QA; or producing corresponding user manual PDF/HTML/InDesign files&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A further inclusion of another ​👋  Dev/Author team!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To achieve this, regular close collaboration is needed. None of what is "supplied" by either team is set in stone - particularly, either team will need adjustments from the other to achieve the goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distinct Pipelines and Deliverables
&lt;/h3&gt;

&lt;p&gt;A way of organising the flow of source-code-to-deliverable is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;​🌱 Identify base component parts - build them and version them as deliverables themselves&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;​🪴  Identify complex parts - consume base parts as one would consume a third-party library, and produce a new versioned deliverable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🌳  Identify a given product - consume base and complex parts as you would consume third-party solutions, and assemble these to produce a versioned deliverable: the software release.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these comprise the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;​📂 A source of dependencies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;base component: a code repo&lt;/li&gt;
&lt;li&gt;complex components: a code repo, and a binaries repo for pre-built dependencies&lt;/li&gt;
&lt;li&gt;Product: usually pre-built dependencies, and some manifest files from a repo&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;​🛠️ A pipeline&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;each level has its own, stand-alone pipeline&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;​📦 A delivery target (file format, and repository location)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;base and complex components: usually a package repository, but an artifacting server/filesystem is equally suitable&lt;/li&gt;
&lt;li&gt;product: usually a package repository, image repo (VMs and OCI/Docker images), cold-storage vault.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;p&gt;There are certainly more considerations than the above, but I wanted to highlight just how much of this is more than just tooling - you could probably put together a full, maintainable solution using just &lt;code&gt;podman&lt;/code&gt;, &lt;code&gt;nginx&lt;/code&gt; and a small-hundreds lines of scripting (and no, I am not setting a challenge to do this! but do feel free...).&lt;/p&gt;

&lt;p&gt;It is about defining scope collectively, cultivating a shared understanding of the goal, and &lt;em&gt;keeping components simple&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
