<?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: Nyctef</title>
    <description>The latest articles on DEV Community by Nyctef (@nyctef).</description>
    <link>https://dev.to/nyctef</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%2F387837%2Fe03ab023-5787-43a6-b4d2-dae6f32dd231.png</url>
      <title>DEV Community: Nyctef</title>
      <link>https://dev.to/nyctef</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nyctef"/>
    <language>en</language>
    <item>
      <title>Automatically resolve formatting conflicts with jj fix</title>
      <dc:creator>Nyctef</dc:creator>
      <pubDate>Fri, 04 Apr 2025 15:26:54 +0000</pubDate>
      <link>https://dev.to/nyctef/automatically-resolve-formatting-conflicts-with-jj-fix-b92</link>
      <guid>https://dev.to/nyctef/automatically-resolve-formatting-conflicts-with-jj-fix-b92</guid>
      <description>&lt;p&gt;Jujutsu (jj) is a git-compatible versioning tool. It makes working with git repositories much nicer, and also supports more advanced workflows that would be difficult or infeasible in git.&lt;/p&gt;

&lt;p&gt;As an example, here's a situation I ran into earlier this week. Let's say we have a class called &lt;code&gt;Answer&lt;/code&gt; which has diverged on two branches. On &lt;code&gt;main&lt;/code&gt;, the class has been reformatted so that we're not indenting everything by the namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Answer&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;GetAnswer&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="m"&gt;54&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;while on a branch, the contents of the method have been changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Answer&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;GetAnswer&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="m"&gt;42&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;If we run &lt;code&gt;jj log&lt;/code&gt; in this situation, we might get output like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ jj log
@  tuwwzvyz nyctef 2 seconds ago b2c07c4d
│  (empty) (no description set)
○  kwuuwuwx nyctef 1 minute ago git_head() 7e2d3b10
│  correct answer
○  lwowvoox nyctef 2 minutes ago 975fb9af
│  another change on this branch
○  svwxvtuo nyctef 3 minutes ago 665dcf1b
│  some change on this branch
│ ◆ xnrtvtyn nyctef 6 minutes ago main 9fd679a9
├─╯  reformat files
◆  kqxstvxn nyctef 7 minutes ago 679659f2
│  previous commit history on main
~  (elided revisions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick primer on the log output: &lt;code&gt;@&lt;/code&gt; shows the change that we're currently editing, which is empty at the moment. After that the log shows the graph of previous changes. Changes marked with &lt;code&gt;◆&lt;/code&gt; are considered to be immutable.&lt;/p&gt;

&lt;p&gt;From left to right, the log shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;○&lt;/code&gt; is a node in the change graph&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kwuuwuwx&lt;/code&gt; is the &lt;em&gt;change&lt;/em&gt; ID. &lt;strong&gt;When editing changes, the change ID stays consistent, but the underlying git commit ID will be updated&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nyctef&lt;/code&gt; is the author of the change&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1 minute ago&lt;/code&gt; is the timestamp of the change&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git_head()&lt;/code&gt; or &lt;code&gt;main&lt;/code&gt; show any references pointing to that change&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;7e2d3b10&lt;/code&gt; shows the current git commit ID for the change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the real terminal output, the first few characters of the change and commit IDs will be bolded, showing the minimum unique prefix. This is handy when typing out these IDs in commands.&lt;/p&gt;




&lt;p&gt;Let's say we want to try fixing the conflict. The choice between merging and rebasing is somewhat arbitrary, but jj has a really nice rebase command so let's show that off. All we have to do is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jj rebase &lt;span class="nt"&gt;--destination&lt;/span&gt; main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the current branch relative to &lt;code&gt;main&lt;/code&gt; will be put on top of it. Jujutsu also has a nice set of arguments for specifying the set of source revisions to move. &lt;strong&gt;Compared to git, arguments are much more consistent between different commands, so they're much easier to remember as well.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In git, we might expect this rebase to stop halfway through once it encounters the conflict. That's not what happens in Jujutsu, though:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ jj rebase -d main
Rebased 4 commits onto destination
Working copy now at: tuwwzvyz 9031b581 (conflict) (no description set)
Parent commit      : kwuuwuwx bd4ca349 (conflict) correct answer
Added 0 files, modified 3 files, removed 0 files
There are unresolved conflicts at these paths:
Answer.cs    2-sided conflict
New conflicts appeared in these commits:
  tuwwzvyz 9031b581 (conflict) (no description set)
  kwuuwuwx bd4ca349 (conflict) correct answer
To resolve the conflicts, start by updating to the first one:
  jj new kwuuwuwx
Then use `jj resolve`, or edit the conflict markers in the file directly.
Once the conflicts are resolved, you may want to inspect the result with `jj diff`.
Then run `jj squash` to move the resolution into the conflicted commit.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we re-run &lt;code&gt;jj log&lt;/code&gt;, we can see that the rebase has actually happened:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ jj log
@  tuwwzvyz nyctef 9 minutes ago 8d02a9f0 conflict
│  (no description set)
×  kwuuwuwx nyctef 9 minutes ago git_head() 5062af7d conflict
│  correct answer
○  svwxvtuo nyctef 9 minutes ago ec16ab36
│  another change on this branch
○  lwowvoox nyctef 9 minutes ago fab09cd9
│  some change on this branch
◆  xnrtvtyn nyctef 28 minutes ago main 9fd679a9
│  reformat files
~  (elided revisions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, our change (and its descendants) are now marked as &lt;code&gt;conflict&lt;/code&gt;s in the log. &lt;strong&gt;Jujutsu treats conflicts as a first-class object, and allows them to exist in the history.&lt;/strong&gt; This means we aren't forced to fix conflicts as soon as they appear, unlike for &lt;code&gt;git merge&lt;/code&gt; or &lt;code&gt;git rebase&lt;/code&gt;. We can take time to fix each problem when necessary and when we have the right information to do so. However, Jujutsu won't let us push commits that contain conflicts to github or another git repo, so we do have to fix them eventually.&lt;/p&gt;

&lt;p&gt;We can also inspect the conflict itself by editing the file locally or using &lt;code&gt;jj show kw&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ jj show k --config ui.conflict-marker-style=git
    ...
   4    4: {
   5    5:     public int GetAnswer()
   6    6:     {
        7: &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; Side #1 (Conflict 1 of 1)
   7    8:         return 54;
        9: ||||||| Base
       10:         public int GetAnswer()
       11:         {
       12:             return 54;
       13:         }
       14: =======
       15:         public int GetAnswer()
       16:         {
       17:             return 42;
       18:         }
       19: &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; Side #2 (Conflict 1 of 1 ends)
   8   20:     }
   9   21: }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can see that the conflict is particularly annoying, because parts of the &lt;code&gt;GetAnswer&lt;/code&gt; function boilerplate are copied both inside and outside the conflict area. If we just try to solve this by picking one side or the other in some merge tool, we're going to end up with broken code. It's not too bad in this toy example, but this problem gets much worse in realistic code.&lt;/p&gt;




&lt;p&gt;Having changes containing conflicts is a bit of a scary state, though, especially if you're new to Jujutsu. It's worth noting another of Jujutsu's killer features: &lt;strong&gt;you can undo any operation using &lt;code&gt;jj op undo&lt;/code&gt; and get the repo back to the previous state.&lt;/strong&gt; If you want to go back further in the history, then you can use &lt;code&gt;jj op log&lt;/code&gt; and &lt;code&gt;jj op restore &amp;lt;revision&amp;gt;&lt;/code&gt; to get there. This is like a supercharged version of git's &lt;code&gt;reflog&lt;/code&gt; command, and it works way more reliably.&lt;/p&gt;

&lt;p&gt;If we ran &lt;code&gt;jj op undo&lt;/code&gt; after the above rebase, and then ran &lt;code&gt;jj log&lt;/code&gt; again, we would see that we're back in the original state with two branches and no conflicts.&lt;/p&gt;




&lt;p&gt;The root of our troubles are the formatting changes on &lt;code&gt;main&lt;/code&gt;: we'd be able to easily resolve the conflicts if those formatting changes were consistently applied to all the changes on our branch. We could add a new change to the branch with some formatting applied, but that wouldn't help with earlier changes. We could go through and edit the changes one by one (this is actually comparatively easy with Jujutsu!) but it would still be a pain for longer branches. Instead, I ended up using &lt;code&gt;jj fix&lt;/code&gt; to solve this problem.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jj fix&lt;/code&gt; (&lt;a href="https://jj-vcs.github.io/jj/latest/cli-reference/#jj-fix" rel="noopener noreferrer"&gt;documented here&lt;/a&gt;) is a command that takes a set of changes to apply to, and then runs various configured tools against each of the files that has a diff in those changes.&lt;/p&gt;

&lt;p&gt;For C# formatting we happen to use &lt;a href="https://www.jetbrains.com/help/resharper/CleanupCode.html" rel="noopener noreferrer"&gt;the Jetbrains CLI&lt;/a&gt;, but this can be configured to work with any formatting tool. &lt;code&gt;jj fix&lt;/code&gt; happens to require a tool which accepts file contents on stdin, and writes the updated file contents to stdout&lt;sup&gt;1&lt;/sup&gt;, so we need a wrapper script to make that work with the jetbrains cli:&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;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="c"&gt;# abort on error&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="c"&gt;# print out commands to help debugging&lt;/span&gt;

&lt;span class="nv"&gt;RAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-dc&lt;/span&gt; A-Za-z0-9 &amp;lt; /dev/random | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 10&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/file-to-format-&lt;/span&gt;&lt;span class="nv"&gt;$RAND&lt;/span&gt;&lt;span class="s2"&gt;.cs"&lt;/span&gt;

&lt;span class="nb"&gt;cat&lt;/span&gt; - &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$FILE&lt;/span&gt;
&lt;span class="c"&gt;# realpath is required since the file isn't part of the solution,&lt;/span&gt;
&lt;span class="c"&gt;# so we need an absolute path to force jb to consider it&lt;/span&gt;
&lt;span class="c"&gt;# https://youtrack.jetbrains.com/issue/RSRP-489150/&lt;/span&gt;
dotnet tool run jb &lt;span class="nt"&gt;--&lt;/span&gt; cleanupcode  &lt;span class="nt"&gt;--no-build&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;realpath&lt;/span&gt; &lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; 1&amp;gt;&amp;amp;2
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="nv"&gt;$FILE&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nv"&gt;$FILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script creates a temporary file, formats it using the JetBrains CLI, and outputs the result. The &lt;code&gt;realpath&lt;/code&gt; command ensures the file is recognized by the formatter, even though it's not part of the solution.&lt;/p&gt;

&lt;p&gt;With that, we can run a command like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jj fix -s k --config fix.tools.jb.command='["./scratch/cleanup-stdin.sh"]' --config fix.tools.jb.patterns='["glob:**/*.cs"]'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to automatically reformat files changed in &lt;code&gt;k&lt;/code&gt; (and its descendants). &lt;code&gt;jj fix&lt;/code&gt; is guaranteed to never introduce new conflicts, but it can fix conflicts in existing changes.&lt;/p&gt;

&lt;p&gt;If we want to run this command more often, we can save the &lt;code&gt;fix.tools&lt;/code&gt; settings to jj's toml config, and they'll automatically get picked up the next time we run &lt;code&gt;jj fix&lt;/code&gt;. We can also use &lt;code&gt;fix.tools.X.enabled&lt;/code&gt; to turn tools on or off as needed.&lt;/p&gt;

&lt;p&gt;Because both branches now have consistent formatting, our merge conflict goes away and the fix can be integrated without issue. Jujutsu saves the day again! 🎉&lt;/p&gt;

&lt;p&gt;If you're curious about trying out Jujutsu, I'd highly recommend &lt;a href="https://jj-vcs.github.io/jj/latest/install-and-setup/" rel="noopener noreferrer"&gt;installing it and giving it a try&lt;/a&gt;. It's compatible with existing git repos, so you don't have to worry about forcing other people to use it as well :)&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnotes
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;In the future &lt;a href="https://jj-vcs.github.io/jj/latest/design/run/" rel="noopener noreferrer"&gt;the proposed &lt;code&gt;jj run&lt;/code&gt; command&lt;/a&gt; may be a better fit for &lt;code&gt;jb cleanupcode&lt;/code&gt;, since it's  designed to work with tools that expect a whole working copy to run against, rather than individual files&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>git</category>
      <category>jujutsu</category>
      <category>versioncontrol</category>
      <category>programming</category>
    </item>
    <item>
      <title>Shapes, slots, and traces: optimizing the property pattern</title>
      <dc:creator>Nyctef</dc:creator>
      <pubDate>Fri, 21 Mar 2025 17:05:06 +0000</pubDate>
      <link>https://dev.to/nyctef/shapes-slots-and-traces-optimizing-the-property-pattern-21c8</link>
      <guid>https://dev.to/nyctef/shapes-slots-and-traces-optimizing-the-property-pattern-21c8</guid>
      <description>&lt;p&gt;A common aspect of dynamic programming languages is the ability to create objects with arbitrary types, and to add or remove properties of these objects at runtime. &lt;/p&gt;

&lt;p&gt;These objects are usually implemented as a hashmap (AKA a hashtable, dictionary or associative array). A hashmap provides amortized constant-time inserts, updates and deletes for properties in an object. However, despite a ton of research that has gone into making hashmaps as fast as possible, they still have substantial overhead due to the requirements to hash property names and search for the matching entries.&lt;/p&gt;

&lt;p&gt;Even in statically typed programming languages, it is often useful to work with unstructured data. For example, in the schema comparison tool we're currently working on, we store the schema objects themselves as nested property bags. This means the core comparison code can be almost entirely generic—just comparing lists of named properties to each other—regardless of which database the schema objects came from.&lt;/p&gt;

&lt;p&gt;Despite the massive expressive power of dynamic objects, it turns out that most objects in most programs end up looking very similar to each other. This insight means there's a bunch of possibilities for optimizing property access on objects—one of the most common operations in any language that has objects—and overcoming the overhead of the naive hashmap implementation.&lt;/p&gt;

&lt;p&gt;I'm only scratching the surface of these optimizations here (and I'll probably get a bunch of the details wrong) but I've linked to some references + further reading that I found useful if you want to dive in more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Javascript: shapes
&lt;/h3&gt;

&lt;p&gt;There are a lot of different Javascript runtimes, but most of them have a similar concept of tracking object shapes (inspired by "Hidden Classes" from the SELF language). Given some code like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which produces a &lt;code&gt;point&lt;/code&gt; object with two properties, a naive implementation might store the object in memory something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object point:
  - number of properties: 2
  - property 0: x
  - property 0 value: 3
  - property 1: y
  - property 1 value: 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first idea behind shapes is that the structure of an object can be stored separately from its contents, which is much more efficient when we have many copies of similar objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shape shapeA:
  - number of properties: 2
  - property 0: x
  - property 1: y

object point:
  - shape: shapeA
  - value 0: 3
  - value 1: 4

[... plus a lot more point values]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a lot more nuance about how shapes are discovered and tracked, which is explained in depth in the links below. For now, though, the other interesting aspect is "Inline Caches". For example, assuming we have a function like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;point&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="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&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 we want to resolve the &lt;code&gt;.x&lt;/code&gt; property on the incoming object, we now have to follow the &lt;code&gt;shape&lt;/code&gt; pointer on the object, and then look up the property descriptor in the list of properties on the shape. But this is still the same kind of slow hashmap lookup we've been trying to avoid! The next trick is to reserve a bit of space in the bytecode to cache shape of the last object that was passed into the function. Then the function gets compiled into something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;point&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="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;shapeA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// a fast pointer comparison&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&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="c1"&gt;// directly index into the object's values&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="c1"&gt;// ... slow path: look up `x` property in `point.shape`&lt;/span&gt;
    &lt;span class="c1"&gt;//     (and then update the cache)&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 inline cache starts out empty, and gets updated when an object with a different shape passes through the function. (For example, the resulting code might compare against &lt;code&gt;shapeC&lt;/code&gt; and access object index &lt;code&gt;.3&lt;/code&gt; instead).&lt;/p&gt;

&lt;p&gt;Since the majority of objects passed into this &lt;code&gt;getX&lt;/code&gt; function probably have the same shape, this turns out to be a useful optimization.&lt;/p&gt;

&lt;h4&gt;
  
  
  references
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mathiasbynens.be/notes/shapes-ics" rel="noopener noreferrer"&gt;https://mathiasbynens.be/notes/shapes-ics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.archive.org/web/20201124042930/https://channel9.msdn.com/Shows/Going+Deep/Expert-to-Expert-Erik-Meijer-and-Lars-Bak-Inside-V8-A-Javascript-Virtual-Machine" rel="noopener noreferrer"&gt;https://web.archive.org/web/20201124042930/https://channel9.msdn.com/Shows/Going+Deep/Expert-to-Expert-Erik-Meijer-and-Lars-Bak-Inside-V8-A-Javascript-Virtual-Machine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Python: &lt;code&gt;__slots__&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Shapes in Javascript relies on the runtime automatically detecting "hidden classes" during the program's execution, but Python is more explicit.&lt;/p&gt;

&lt;p&gt;By default, every python object has a hashmap attached (named &lt;code&gt;__dict__&lt;/code&gt;) where the object's properties are stored. Arbitrary properties can be added and removed from objects later:&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;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&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;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# prints {'bar': 3}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To optimize memory usage and potentially improve performance, Python provides the &lt;code&gt;__slots__&lt;/code&gt; declaration. By defining &lt;code&gt;__slots__&lt;/code&gt; in a class, you can explicitly declare data members (like properties) and prevent the creation of the default &lt;code&gt;__dict__&lt;/code&gt; for each instance. This can save memory and make attribute access faster because the properties are stored in a more compact structure.&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="n"&gt;__slots__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bar&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&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;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# prints 3
&lt;/span&gt;
&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;# AttributeError: 'Foo' object has no attribute 'baz'
&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;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# AttributeError: 'Foo' object has no attribute '__dict__'.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's hard to tell exactly how much slots speeds up attribute access, and reports vary. In particular the cpython bytecode for slots vs non-slots is the same:&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;get_bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get_bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# prints 3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dis&lt;/span&gt;
&lt;span class="n"&gt;dis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# disassemble the bytecode of `get_bar`
# prints the following:
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
  2           0 LOAD_FAST                0 (obj)
              2 LOAD_ATTR                0 (bar)
              4 RETURN_VALUE
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;here &lt;code&gt;LOAD_FAST&lt;/code&gt; puts the first parameter on the stack, &lt;code&gt;LOAD_ATTR&lt;/code&gt; calls &lt;code&gt;getattr(top_of_stack, "bar")&lt;/code&gt; and &lt;code&gt;RETURN_VALUE&lt;/code&gt; returns the top of the stack out of the function.&lt;/p&gt;

&lt;p&gt;The implementation for &lt;code&gt;getattr&lt;/code&gt; ultimately ends up going down different paths based on whether it needs to look up an attribute in &lt;code&gt;__dict__&lt;/code&gt; or in slots.&lt;/p&gt;

&lt;h4&gt;
  
  
  references
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tenthousandmeters.com/blog/python-behind-the-scenes-6-how-python-object-system-works/" rel="noopener noreferrer"&gt;https://tenthousandmeters.com/blog/python-behind-the-scenes-6-how-python-object-system-works/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/reference/datamodel.html#slots" rel="noopener noreferrer"&gt;https://docs.python.org/3/reference/datamodel.html#slots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@stephenjayakar/a-quick-dive-into-pythons-slots-72cdc2d334e" rel="noopener noreferrer"&gt;https://medium.com/@stephenjayakar/a-quick-dive-into-pythons-slots-72cdc2d334e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://python-history.blogspot.com/2010/06/inside-story-on-new-style-classes.html" rel="noopener noreferrer"&gt;https://python-history.blogspot.com/2010/06/inside-story-on-new-style-classes.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3.10/library/dis.html#opcode-LOAD_ATTR" rel="noopener noreferrer"&gt;https://docs.python.org/3.10/library/dis.html#opcode-LOAD_ATTR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  LuaJIT: traces
&lt;/h3&gt;

&lt;p&gt;LuaJIT is a Just-In-Time (JIT) compiler for Lua that uses a technique called tracing to optimize code execution. Unlike many JIT compilers which compile a method at a time, tracing JIT compilers work by recording the operations performed during the execution of "hot" loops or frequently executed code paths. These traces can span across many methods and layers of abstraction, making optimizations such as devirtualization much easier than they would be otherwise. Once a hot path is identified, the JIT compiler generates optimized code for that specific path, which can then be executed much faster than the original interpreted code.&lt;/p&gt;

&lt;p&gt;In LuaJIT, traces are sequences of instructions that represent the execution flow of a program. When a loop or function is executed multiple times, LuaJIT starts recording a trace of the operations performed. This trace is then compiled into highly optimized asesembly. The trace will largely be linear, with lots of guard clauses on conditionals checking that the current execution of the code is going down the same path as the trace. If any of these guard clauses fail, LuaJIT can fall back to the interpreter (which may cause new traces to be recorded) or continue with a side trace.&lt;/p&gt;

&lt;p&gt;Tracing JIT vs more traditional method-based JITs are an interesting tradeoff. Since the traces that LuaJIT records generally don't have branches, and can span across wide areas of code, a lot of optimizations become much easier or trivial. On the other hand, the runtime can spend a long time interpreting bytecode and recording data before it's able to start compiling traces, so warmup time is much worse. Tracing JIT can also perform poorly in situations where branches are hard to predict. Some browsers have moved away from tracing JIT as a result, while others are using "meta-JIT" frameworks that combine per-method and tracing JITs at various levels of optimization.&lt;/p&gt;

&lt;p&gt;For our purposes, we're interested in how LuaJIT optimizes constant attribute lookups. Let's take a look at some lua code this time:&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="n"&gt;point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;-- this defines a table with two named attributes&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;point&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;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;x&lt;/code&gt; is a constant attribute in this case, LuaJIT can emit a &lt;code&gt;HREFK&lt;/code&gt; ("constant hash reference") opcode into its IR while compiling. The IR is what then gets transformed into machine-specific assembly code. The trick is that the &lt;code&gt;HREFK&lt;/code&gt; instruction also includes the number of the slot in the table's hashmap where the entry is expected. If the key stored in that slot matches the expectation, then the program can skip the entire hash lookup algorithm and the trace can continue. Otherwise, the program will fall back to the slow path.&lt;/p&gt;

&lt;p&gt;LuaJIT includes tools (particularly &lt;code&gt;-jdump&lt;/code&gt;) that we can use to inspect the recorded trace, along with the IR and machine code that gets generated for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;luajit &lt;span class="nt"&gt;-jdump&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
point = { x = 3, y = 4}

function getX(point) return point.x; end

for i=1,1000000 do getX(point) end -- a big loop to force a trace to happen
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  references
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/20266523/how-does-luajits-trace-compiler-work" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/20266523/how-does-luajits-trace-compiler-work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freelists.org/post/luajit/How-does-LuaJITs-trace-compiler-work,1" rel="noopener noreferrer"&gt;https://www.freelists.org/post/luajit/How-does-LuaJITs-trace-compiler-work,1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lua-users.org/lists/lua-l/2009-11/msg00089.html" rel="noopener noreferrer"&gt;http://lua-users.org/lists/lua-l/2009-11/msg00089.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.cloudflare.com/luajit-hacking-getting-next-out-of-the-nyi-list/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/luajit-hacking-getting-next-out-of-the-nyi-list/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tarantool/tarantool/wiki/LuaJIT-SSA-IR#memory-references" rel="noopener noreferrer"&gt;https://github.com/tarantool/tarantool/wiki/LuaJIT-SSA-IR#memory-references&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/LuaJIT/LuaJIT/blob/538a82133/src/lj_record.c#L1465-L1478" rel="noopener noreferrer"&gt;https://github.com/LuaJIT/LuaJIT/blob/538a82133/src/lj_record.c#L1465-L1478&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pypy.org/posts/2025/01/musings-tracing.html" rel="noopener noreferrer"&gt;https://pypy.org/posts/2025/01/musings-tracing.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What should you use?
&lt;/h3&gt;

&lt;p&gt;Given all of the above, it's unlikely that you're optimizing your own programming language (and if you are, you could probably do a better job writing this blog post! :)&lt;/p&gt;

&lt;p&gt;In cases like a schema comparison tool, though (where we're storing objects as property bags but have some additional knowledge about their structure) there's a lot of potential improvements that can be done by implementing something similar to &lt;code&gt;__slots__&lt;/code&gt; in Python.&lt;/p&gt;

&lt;p&gt;It's not a critical performance improvement right now (hashmaps are already pretty fast, after all) but it's definitely something I want to keep an eye on.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other references:
&lt;/h4&gt;

&lt;p&gt;On the property pattern in general:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html" rel="noopener noreferrer"&gt;https://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>performance</category>
      <category>javascript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Building a cli parser from scratch</title>
      <dc:creator>Nyctef</dc:creator>
      <pubDate>Sat, 11 Jul 2020 17:25:46 +0000</pubDate>
      <link>https://dev.to/nyctef/building-a-cli-parser-from-scratch-4mme</link>
      <guid>https://dev.to/nyctef/building-a-cli-parser-from-scratch-4mme</guid>
      <description>&lt;p&gt;There are plenty of CLI parser libraries out there for pretty much every programming language under the sun. However, sometimes you might not find one with the right combination of features you want, or maybe you just want to understand what makes them tick. Building a CLI parser is probably much easier than you think!&lt;br&gt;
To begin with, we're going to assume we're passed some arguments as a string array, and we don't have to worry about &lt;a href="https://devblogs.microsoft.com/oldnewthing/20100917-00/?p=12833" rel="noopener noreferrer"&gt;any complicated shell escaping rules&lt;/a&gt;! This makes our life much easier already.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick note&lt;/strong&gt;: I’ll try to stick to the convention of talking about “parameters” for the various options we define, and “arguments” for the actual values passed to those parameters.&lt;/p&gt;
&lt;h2&gt;
  
  
  Our first CLI parser
&lt;/h2&gt;

&lt;p&gt;Let’s assume that we want to handle a decent number of possible parameters, and some (or all) of those parameters might be optional. If we only want to handle a small, fixed number of &lt;strong&gt;positional parameters&lt;/strong&gt;, you can usually get away with something pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleArgs&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&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;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;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="n"&gt;Length&lt;/span&gt; &lt;span class="p"&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;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Usage: foo.exe [api key] [target]"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiKey&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="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;target&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="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="c1"&gt;// do something with apiKey and target...&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&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;Instead, let's imagine we want to switch to named parameters like &lt;code&gt;--apiKey&lt;/code&gt; and &lt;code&gt;--target&lt;/code&gt; to make code using the CLI more readable.&lt;br&gt;
The main complication is we can now specify the arguments in either order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; foo.exe --apiKey abcd1234 --target production
&amp;gt; foo.exe --target production --apiKey abcd1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key thing to notice here is that we always &lt;strong&gt;alternate between a parameter name and an argument value&lt;/strong&gt;. Instead of addressing specific &lt;code&gt;args&lt;/code&gt; elements directly, we’ll iterate through the list and match up each argument with the right parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArgsLoop&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&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;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;currentParameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentParameter&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;currentParameter&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;continue&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;currentParameter&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"--apiKey"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;apiKey&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="n"&gt;currentParameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="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;currentParameter&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"--target"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;currentParameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unexpected arg "&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="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Got &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; and &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="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="m"&gt;0&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;In this loop &lt;code&gt;currentParameter&lt;/code&gt; acts as a &lt;strong&gt;tiny state machine&lt;/strong&gt;: either it’s set to some value and we’re expecting an argument value next, or it’s unset and we’re expecting a parameter name next.&lt;/p&gt;

&lt;p&gt;We’re pretty close to making this into a generic parser! The next key insight comes from the design of CLI parser libraries like &lt;code&gt;NDesk.Options&lt;/code&gt; or &lt;code&gt;Mono.Options&lt;/code&gt;: we want to provide a list of parameter names and a callback for each one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Parameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;
                       &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GenericLoop&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&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;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Parameters&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"--apiKey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"--target"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Got &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; and &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="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="m"&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;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt; &lt;span class="n"&gt;parameters&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="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;currentParameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentParameter&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;currentParameter&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="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentParameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                            &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;callback&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="n"&gt;currentParameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unexpected value: "&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="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;And that’s it! We could totally stop here if we wanted. But there’s plenty of improvements we can make from this point, too.&lt;/p&gt;

&lt;p&gt;With a slight tweak, we can allow for parameters which don’t take a value. This is useful for boolean flags like &lt;code&gt;--quiet&lt;/code&gt; and similar. First we add the new parameter to our list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Parameters&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"--apiKey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"--target"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"--silent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&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;(Note how the new callback ignores values given to it and just sets the flag.)&lt;/p&gt;

&lt;p&gt;Secondly, we change the loop to prioritize matching parameter names over satisfying parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt; &lt;span class="n"&gt;parameters&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="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;currentCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&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;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// if the previous arg was a parameter name, then it&lt;/span&gt;
                &lt;span class="c1"&gt;// has no value&lt;/span&gt;
                &lt;span class="n"&gt;currentCallback&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;currentCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentCallback&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;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;// This arg doesn't match any parameter names, so it&lt;/span&gt;
                &lt;span class="c1"&gt;// must be an argument value.&lt;/span&gt;
                &lt;span class="nf"&gt;currentCallback&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="n"&gt;currentCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unexpected value: "&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="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;currentCallback&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;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;// we've run out of arguments to pass, but there's still&lt;/span&gt;
            &lt;span class="c1"&gt;// a pending parameter&lt;/span&gt;
            &lt;span class="nf"&gt;currentCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&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;Previously, if we saw arguments like &lt;code&gt;foo.exe --target --apiKey&lt;/code&gt;, then we would have assumed that &lt;code&gt;"--apiKey"&lt;/code&gt; was the value passed to &lt;code&gt;--target&lt;/code&gt;. The updated code will invoke both callbacks for &lt;code&gt;--target&lt;/code&gt; and &lt;code&gt;--apiKey&lt;/code&gt; with &lt;code&gt;null&lt;/code&gt; instead. The advantage is we can now call a CLI like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; foo.exe --silent --apiKey abcd1234 --target staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and all the values will get set correctly, even though &lt;code&gt;--silent&lt;/code&gt; didn’t get passed a value.&lt;/p&gt;




&lt;h2&gt;
  
  
  Personalizing your parser
&lt;/h2&gt;

&lt;p&gt;It might not look like much, but this little loop can be the foundation for a lot of parser features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now that we have a programmatic list of all the arguments, we can generate help text when something goes wrong, or if the user specifies a &lt;code&gt;--help&lt;/code&gt; argument. We could also add description text for each of the parameters and print that out too.&lt;/li&gt;
&lt;li&gt;Error handling can be a bit tricky: we need to either throw and catch a custom &lt;code&gt;ShowHelpException&lt;/code&gt;, or stop the process ourselves with &lt;code&gt;Environment.Exit(1)&lt;/code&gt;. Both methods work but have their own problems, so play with them and see which is the best fit for your case.&lt;/li&gt;
&lt;li&gt;Currently if we want to have multiple aliases for each parameter, we need to repeat the whole parameter definition including the callback. A nice quality of life feature is supporting multiple aliases within the parameter spec, so eg &lt;code&gt;"-q|--quiet"&lt;/code&gt; provides two alternatives for a quiet parameter.&lt;/li&gt;
&lt;li&gt;One extra feature we needed was environment variable support for passing more sensitive arguments. Extending the above idea, we assumed environment variables followed a &lt;code&gt;SHOUTY_SNAKE_CASE&lt;/code&gt; convention, so used parameter specs like &lt;code&gt;"-p|--password|DATABASE_PASSWORD"&lt;/code&gt;. Environment variables get checked first, so they can be overridden by cli arguments later if required.&lt;/li&gt;
&lt;li&gt;The loop currently only supports named parameters, but we can add support for positional parameters too. The trick is to keep a separate queue of positional parameters, then check whether there are any remaining before carrying on with the error case:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// track how many positional parameters have been consumed    &lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// ... same loop as before ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;    
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;positionalParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;                  
        &lt;span class="n"&gt;positionalParams&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Handler&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="n"&gt;position&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="c1"&gt;// and raise error as before&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We only support string parameters, but you can easily add support for other parameter types. Just wrap the callbacks in code which implements parsing for integers, enums, &lt;code&gt;FileInfo&lt;/code&gt;s or any other custom type you need. You may find it helpful to replace the dictionary with a list of &lt;code&gt;Parameter&lt;/code&gt; classes, then subclass for &lt;code&gt;BoolParameter&lt;/code&gt;, &lt;code&gt;IntParameter&lt;/code&gt; and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s just a brief and incomplete list — once you have your own parser code that you’re fully in control of, you can implement as many or as few features as you need! I’d recommend starting off as minimal as possible. Don’t be afraid to implement one-off features outside the parser at first. Aim to convert these features into generic parser code once you have a few examples to guide you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reflection-based parsing
&lt;/h2&gt;

&lt;p&gt;So our callback-based parser, while nice and simple to implement, isn’t very ergonomic. We have to set up a bunch of mutable variables, call the parser to populate them, and then manually verify that required parameters have a value. We’ll probably also want to also bundle the variables up into an options object to pass to the rest of the program.&lt;/p&gt;

&lt;p&gt;What modern CLI parsing libraries tend to implement is something a bit more “magic.” They let us decorate a class representing the various parameters with attributes for how each parameter is specified, and then automatically create an instance of that class. Let’s dig in to how we might actually implement this using reflection in C#: other languages will differ, but the main concepts should be the same.&lt;/p&gt;

&lt;p&gt;This process is going to consist of four steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use reflection to inspect the passed-in class, and find the attributes with parameter specifications.&lt;/li&gt;
&lt;li&gt;Build a callback-based parser with the list of parameters we’ve discovered, and implement callbacks that store the argument values in some intermediate bucket.&lt;/li&gt;
&lt;li&gt;Run the callback-based parser against the args list.&lt;/li&gt;
&lt;li&gt;Use reflection again to call the class’s constructor with the list of parameters‍ from the parser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we’re done we’ll be able to define a class like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-a|--apiKey|FOO_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ApiKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&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="nf"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-t|--target"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Target&lt;/span&gt; &lt;span class="n"&gt;Target&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&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="nf"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-s|--silent"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;Silent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Target&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Silent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;false&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 have our parser output nicely immutable, ready-to-go instances from the CLI arguments.&lt;/p&gt;

&lt;p&gt;First we need to define a new attribute type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParameterAttribute&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Attribute&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Spec&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ParameterAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Spec&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spec&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;It’s pretty minimal — if you want you can add extra properties like some help text to make it more friendly. We’ll just be passing the values down into our callback parser, anyway.&lt;/p&gt;

&lt;p&gt;Let’s get started with the actual Parse method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&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;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;
    &lt;span class="err"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;var&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;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="n"&gt;p&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;attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetCustomAttribute&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ParameterAttribute&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing to notice is that the method is static and generic. The &lt;code&gt;T&lt;/code&gt; type parameter gives us an implicit reference to the type of parameter object to create. The &lt;code&gt;typeof&lt;/code&gt; operator turns the implicit reference into an explicit value that we can inspect. Next, we search the list of properties on the type and find those with a &lt;code&gt;Parameter&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Once we have a set of parameters with their matching C# properties, we need to find a constructor which has an equivalent list of parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;propNames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConstructors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ConstructorMatchesProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;propNames&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Single&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that once we’ve parsed all the parameters, we should have a set of values to call the constructor with. We assume that the constructor will do the obvious thing and pass its arguments to the equivalent properties, but the constructor is also allowed to implement extra behavior like default values. This will come in handy later when we want to implement optional parameters.&lt;/p&gt;

&lt;p&gt;Some other libraries assume a different convention, and &lt;a href="https://github.com/commandlineparser/commandline/issues/188" rel="noopener noreferrer"&gt;require the constructor parameters to match the order of properties on the class&lt;/a&gt;, but this feels a bit more fragile to me. Of course, given you control this code you can make whatever implementation decisions are best for you :)&lt;/p&gt;

&lt;p&gt;The next step is to build up the underlying parser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;argsBucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&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;object&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;(&lt;/span&gt;
            &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;StringComparer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Spec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;argsBucket&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prop&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="n"&gt;x&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;Previously we had explicit variables to hold the results of each callback, but now we collect everything into a big &lt;code&gt;Dictionary&lt;/code&gt;. The store here needs to be case-insensitive, since in C# constructor parameters and property names will have different case by convention.&lt;/p&gt;

&lt;p&gt;Once that’s all set up, we just run the parser we built earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="n"&gt;CallbackParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and &lt;code&gt;argsBucket&lt;/code&gt; should be filled with all the values from the commandline.&lt;/p&gt;

&lt;p&gt;At this point we can do something new: check for required parameters. We’re still in the parser code and we have a reference to all of the argument values, which we didn’t have before with the callback-based parser.&lt;/p&gt;

&lt;p&gt;Usually we’d use a &lt;code&gt;ParameterAttribute&lt;/code&gt; property to make parameters required or optional, but with C#’s new nullable reference types we can go one better and use a language feature. The nullability of each constructor parameter tells us whether the relevant option is required. This is a bit unintuitive (why don’t we use the nullability of the properties themselves?) but it means we can easily put default values in the constructor, like how &lt;code&gt;--silent&lt;/code&gt; defaults to &lt;code&gt;false&lt;/code&gt; in the example above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;      &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;requiredParams&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;constructorParams&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
      &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameterInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;requiredParams&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;argsBucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ContainsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameterInfo&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="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing argument: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Spec&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argsBucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetValueOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameterInfo&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;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing argument value: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Spec&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&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="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/nyctef/b9c69ee44cebc7df9cc0eaab9c9a5076" rel="noopener noreferrer"&gt;Here’s an implementation of that &lt;code&gt;Utils.IsNullable&lt;/code&gt; function&lt;/a&gt; — it’s a bit too big to include inline!&lt;/p&gt;

&lt;p&gt;After all that, the actual magic part is a bit underwhelming. We build up the array of constructor arguments, invoke the selected constructor, and cast the result to the output type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;constructorArgs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetParameters&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;argsBucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetValueOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;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;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constructorArgs&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’s it! To use this, we just call &lt;code&gt;Parse&amp;lt;Example&amp;gt;(args)&lt;/code&gt;, and get a constructed &lt;code&gt;Example&lt;/code&gt; object with all the properties filled in. I think you’ll agree this is a much nicer interface to work with.&lt;/p&gt;




&lt;p&gt;To sum up, hopefully you’ve seen a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can build a simple CLI parser in a few lines of code.&lt;/li&gt;
&lt;li&gt;Once we have our own CLI parser, we can add features much more easily compared to a third-party library.&lt;/li&gt;
&lt;li&gt;We can use reflection to provide a much nicer “magic” parsing style, while building on top of a simpler parser.
If you want more, you might also like &lt;a href="https://medium.com/ingeniouslysimple/building-a-virtualized-list-from-scratch-9225e8bec120" rel="noopener noreferrer"&gt;“Building a virtualized list from scratch”&lt;/a&gt;, or Gary Bernhardt’s excellent &lt;a href="https://www.destroyallsoftware.com/screencasts" rel="noopener noreferrer"&gt;FROM SCRATCH&lt;/a&gt; screencasts which inspired these posts!&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was originally posted &lt;a href="https://medium.com/ingeniouslysimple/building-a-cli-parser-from-scratch-a2beba0d9fcb?source=friends_link&amp;amp;sk=84c956c1969a338b7df530d9d8d1aa94" rel="noopener noreferrer"&gt;on Ingeniously Simple&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>parser</category>
      <category>fromscratch</category>
      <category>csharp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Better living through git aliases</title>
      <dc:creator>Nyctef</dc:creator>
      <pubDate>Thu, 04 Jun 2020 08:35:05 +0000</pubDate>
      <link>https://dev.to/nyctef/better-living-through-git-aliases-2ajm</link>
      <guid>https://dev.to/nyctef/better-living-through-git-aliases-2ajm</guid>
      <description>&lt;p&gt;There are many varied and wonderful git clients available, but by far the fastest, most flexible and most extensible is the &lt;code&gt;git&lt;/code&gt; commandline itself. The problem is that it's ... a bit of a mess. There have been some improvements over the years, like &lt;a href="https://stackoverflow.com/q/21839651" rel="noopener noreferrer"&gt;changing &lt;code&gt;push.default&lt;/code&gt;'s default&lt;/a&gt; and &lt;a href="https://www.infoq.com/news/2019/08/git-2-23-switch-restore/" rel="noopener noreferrer"&gt;splitting &lt;code&gt;git checkout&lt;/code&gt; in two&lt;/a&gt;. But there are still fundamental problems, like the same concept being referred to as the &lt;a href="https://git-scm.com/docs/git-add" rel="noopener noreferrer"&gt;"index"&lt;/a&gt;, &lt;a href="https://git-scm.com/docs/git-restore#Documentation/git-restore.txt---staged" rel="noopener noreferrer"&gt;"staging area"&lt;/a&gt; or &lt;a href="https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-emgitdiffemltoptionsgt--cachedltcommitgt--ltpathgt82308203" rel="noopener noreferrer"&gt;"cache"&lt;/a&gt; depending on the command.&lt;/p&gt;

&lt;p&gt;Fortunately, we can mitigate a lot of the problems with &lt;code&gt;git&lt;/code&gt; using &lt;a href="https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases" rel="noopener noreferrer"&gt;aliases&lt;/a&gt;. A personalized set of aliases can help you be much more productive. I’m going to take you through some of the aliases I’ve created so far, but I recommend starting with the default git commands for a while and gradually introducing aliases as you see fit. One of the great things about aliases is they can become completely personal to the way you want to work.&lt;/p&gt;

&lt;p&gt;There are a couple of ways to create aliases. You can create them on the commandline using something like &lt;code&gt;git config --global alias.co checkout&lt;/code&gt;, or you can edit aliases in a text editor by running &lt;code&gt;git config --global --edit&lt;/code&gt;. This will open an editor for your user-wide git config, where aliases will be in the &lt;code&gt;[alias]&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;If you're ever unsure about what an alias does, then &lt;code&gt;git help&lt;/code&gt; will quickly expand the alias for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; git help di
'di' is aliased to 'diff --color-words'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The simplest kind of aliases reduce the typing needed for some other command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;st = status
ci = commit --verbose
fa = fetch --all
co = checkout
di = diff --word-diff
amend = commit --amend
ama = commit --amend -a --no-edit
aa = add -A
mt = mergetool
rhard = reset --hard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This next one is pretty incomprehensible! It produces a useful git log that shows branches with one line per commit, much like you'd get in a UI client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lg = log --graph --abbrev-commit --decorate --date=relative --format=format:'%h%C(reset) - %C(bold green)(%ar)%C(reset) %s%C(reset) %C(bold green)- %an%C(reset)%C(bold yellow)%d%C(reset)'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the log will expand to fill the terminal and let you page through the history. If you're looking for a recent commit you can limit the output with an extra option: &lt;code&gt;git lg -20&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The next few aliases I use get a bit more complicated. You can combine aliases with other options, or make variants of the aliases like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cia = commit --verbose -a
cip = commit --verbose -p
dc = diff --cached --word-diff
fap = fetch --all --prune
cob = checkout -b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next alias is pretty important. &lt;a href="https://felipec.wordpress.com/2014/05/27/is-git-pull-broken/" rel="noopener noreferrer"&gt;Git pull is broken&lt;/a&gt;, so I've aliased &lt;code&gt;git p&lt;/code&gt; to a safe version. Since I'm lazy and it's fewer characters to type, I'll generally do the right thing :)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p = pull --ff-only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens if the above command fails to do a fast-forward? Well you might need to rebase, or merge, or you might just decide to discard your current branch and update to the version of the branch from the remote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rhu = reset --hard @{upstream}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;@{upstream}&lt;/code&gt; is a useful alias for whatever the remote tracking branch is (usually &lt;code&gt;origin/foo&lt;/code&gt; for some branch &lt;code&gt;foo&lt;/code&gt;). It's a bit fiddly to type, though, so having the alias here is especially handy.&lt;/p&gt;

&lt;p&gt;This next one lets you do a fast-forward on master while a different branch is currently checked out. Useful when other people have pushed changes to master that you want in your branch, since you don't need to switch branches before rebasing or merging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fomm = fetch origin master:master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used to have an alias like &lt;code&gt;dlast = diff HEAD^ HEAD --word-diff&lt;/code&gt; for checking the contents of a commit that just happened, but later I discovered &lt;code&gt;git show&lt;/code&gt; without any arguments will do the same thing :)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hg outgoing&lt;/code&gt; and &lt;code&gt;hg incoming&lt;/code&gt; are a couple of commands I used to really miss from mercurial, but haven't used much in the last few years. These days it's rare that we'll have multiple people committing to the same branch, but they might still be useful to other people.&lt;/p&gt;

&lt;p&gt;These aliases are a little more complicated than the previous ones - the &lt;code&gt;!&lt;/code&gt; at the beginning means "pass this to the shell" rather than just being a direct alias for another command. In this case we immediately run &lt;code&gt;git&lt;/code&gt; again, but we could potentially use other commands as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;outgoing = !git lg FETCH_HEAD..
incoming = !git fetch &amp;amp;&amp;amp; git lg ..FETCH_HEAD
outin = !git fa &amp;amp;&amp;amp; git lg --left-right ...FETCH_HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's another one I haven't used in a few years, but has been especially useful in the past:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addw = !git diff -b | git apply --ignore-whitespace --cached
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Short for “add-whitespace-insensitive”: stage changes while ignoring whitespace. Really useful when certain editors don't like whatever line endings you're using and decide to flip them over. Note: this breaks in powershell, since powershell implicitly changes strings in its pipeline to all have CRLF line endings! 🤦&lt;/p&gt;

&lt;p&gt;Has this ever happened to you?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git push
fatal: The current branch foo has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin foo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's super annoying, and while &lt;a href="https://github.com/nvbn/thefuck" rel="noopener noreferrer"&gt;there are more amusing solutions&lt;/a&gt; I like the following alias, which figures out the current branch name and automatically inserts it into the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;puom = !git push --set-upstream origin `git rev-parse --abbrev-ref HEAD`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you just have to remember to use &lt;code&gt;git puom&lt;/code&gt; instead of &lt;code&gt;git push&lt;/code&gt; for the first push of a new branch.&lt;/p&gt;

&lt;p&gt;And one final one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix-master = update-ref refs/heads/master origin/master HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fix-master&lt;/code&gt; is useful when you start making commits, but realize you forgot to make a branch! You can checkout a new branch to point at the commit you're currently on, then use &lt;code&gt;fix-master&lt;/code&gt; to repoint the &lt;code&gt;master&lt;/code&gt; branch back where it should be.&lt;/p&gt;

&lt;p&gt;A side note: If you’re working on windows, there’s a couple of things you’ll want in order to make the commandline actually pleasant to use. The first is a decent shell. This can be powershell, git bash or something similar - you'll probably want to avoid the default cmd unless you're already used to it. The second is a decent console to run the shell in. I've used ConEmu in the last few years and grown to love it, but &lt;a href="https://github.com/microsoft/terminal" rel="noopener noreferrer"&gt;Microsoft are finally investing in a new terminal&lt;/a&gt; which looks very promising.&lt;/p&gt;

&lt;p&gt;Other useful links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://haacked.com/archive/2014/07/28/github-flow-aliases/" rel="noopener noreferrer"&gt;http://haacked.com/archive/2014/07/28/github-flow-aliases/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.wiki.kernel.org/index.php/Aliases" rel="noopener noreferrer"&gt;https://git.wiki.kernel.org/index.php/Aliases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What other useful aliases can you come up with? Post your favorites in the comments :)&lt;/p&gt;

</description>
      <category>git</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Extracting game text from Nier:Automata</title>
      <dc:creator>Nyctef</dc:creator>
      <pubDate>Sat, 30 May 2020 20:01:47 +0000</pubDate>
      <link>https://dev.to/nyctef/extracting-game-text-from-nier-automata-1gm0</link>
      <guid>https://dev.to/nyctef/extracting-game-text-from-nier-automata-1gm0</guid>
      <description>&lt;p&gt;[Originally published in 2018]&lt;/p&gt;

&lt;p&gt;Recently I’ve been playing through Nier:Automata again, and trying to stick to Japanese for more of the playthrough. This is a bit of a challenge since my level of Japanese comprehension is still roughly about that of a two-year-old baby. I ended up taking a lot of screenshots like the one above and then &lt;a href="https://jisho.org/search/%E6%B0%97%E5%88%86%E3%81%8C%E8%89%AF%E3%81%8F%E3%81%A6%E3%82%82%E8%89%AF%E3%81%8F%E3%81%AA%E3%81%8F%E3%81%A6%E3%82%82%E3%80%81%E4%BD%9C%E6%88%A6%E3%81%AB%E3%81%AF%E9%96%A2%E4%BF%82%E3%81%AA%E3%81%84%E3%80%82" rel="noopener noreferrer"&gt;figuring out how to translate them&lt;/a&gt; after the fact.&lt;/p&gt;

&lt;p&gt;This started me wondering, though - surely all these subtitles were tucked away in the game files and could be extracted if we just had the right tools. And it turns out there’s a pretty dedicated mod community that does stuff just like this. After some investigation, I found two useful repos - &lt;a href="https://github.com/nyctef/CriPakTools/" rel="noopener noreferrer"&gt;CriPakTools&lt;/a&gt; and &lt;a href="https://github.com/nyctef/att" rel="noopener noreferrer"&gt;att&lt;/a&gt; - which handled pulling apart the games archive format and then the individual data files respectively. We can chain them together with a quick powershell script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;att&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outDir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;new-item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outDir&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;C:\git\micktu-att\x64\Debug\att.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$inDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outDir&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;cripakexport&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outDir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;new-item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outDir&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;C:\git\wmltogether-CriPakTools\CriPakTools\bin\Debug\CriPakTools.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$inFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outDir&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;gci&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;G:\SteamLibrary\steamapps\common\NieRAutomata\data\&lt;/span&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="nf"&gt;cpk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;cripakexport&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;F:\nier_unpacked_2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;att&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;F:\nier_unpacked_2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;F:\nier_unpacked_2_extracted&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and get a nested folder structure full of files like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
ID: M5920_S0100_G0040_001_op60
JP: いえいえ、そうではなくて。天気がいいと気分が良いのかなー、なんて。
EN: Not really! I just figured it might feel nice to have some good weather.
RU: 

ID: M5920_S0100_G0050_001_a2b
JP: 気分が良くても良くなくても、作戦には関係ない。
EN: Feeling nice has no bearing on completing missions.
RU: 

ID: M5920_S0100_G0060_001_op60
JP: ははっ……２Ｂさんらしいですね。
EN: Hee hee! That is so like you, 2B.
RU: 
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with the matching subtitle lines for English and Japanese, along with a &lt;code&gt;RU:&lt;/code&gt; line (I believe the original author was working on a Russian translation)&lt;/p&gt;

&lt;p&gt;This is already useful, but now we have a folder full of plain text files we can do some fun analysis, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$folder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"F:\nier_unpacked_2_extracted"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gci&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$folder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PSIsContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$fileContents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;utf8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fullname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$fileContents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^JP: (.*)$"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$matches&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="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$chars&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToCharArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$chars&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;group-object&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$totals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sort-object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-desc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-property&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which finds the most common characters on all the lines in all files which begin with &lt;code&gt;JP:&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Count Name                      Group                           
----- ----                      -----                               
11496 。                         {。, 。, 。, 。...}
11445 …                          {…, …, …, …...}
 9108 の                         {の, の, の, の...}                      
 8533 い                         {い, い, い, い...}
 6542 、                         {、, 、, 、, 、...}
 6529 て                         {て, て, て, て...}
 6401 に                         {に, に, に, に...}

 ...

  190 兵                         {兵, 兵, 兵, 兵...}                    
  185 話                         {話, 話, 話, 話...}                     
  185 奨                         {奨, 奨, 奨, 奨...}
  184 的                         {的, 的, 的, 的...}
  184 墟                         {墟, 墟, 墟, 墟...}

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

&lt;/div&gt;



&lt;p&gt;which is pretty neat. Obviously we get basic kana all over the top of the chart, but further down we start getting kanji like &lt;code&gt;体&lt;/code&gt; (body), &lt;code&gt;機&lt;/code&gt; (machine/mechanism/chance), &lt;code&gt;生&lt;/code&gt; (life) and &lt;code&gt;命&lt;/code&gt; (life/fate). A lot of these kanji end up in &lt;code&gt;機械生命体&lt;/code&gt; (lit. machine-lifeform), the name of the enemies in this game, &lt;a href="https://www.youtube.com/watch?v=fCn8zs912OE" rel="noopener noreferrer"&gt;which is probably not a coincidence&lt;/a&gt;. As you’d expect, the counts of character frequencies definitely look like they form some sort of power law distribution.&lt;/p&gt;

&lt;p&gt;Anyway, this ended up being a pretty fun programming diversion - hopefully this’ll turn out to be a useful resource for learning more sentences.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>nierautomata</category>
      <category>japanese</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
