<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel><title>Siderite's Blog</title>
<description>I am a .NET C# developer and this is my personal and technical blog.</description>
<generator>Miniblog.Core</generator>
<link>https://siderite.dev/</link>
<item>
  <title>Two finger tap for right-click</title>
  <link>https://siderite.dev/blog/two-finger-tap-for-right-click/</link>
  <description>&lt;p&gt;&amp;nbsp; For a long time I've used laptop touchpads with the buttons that were placed somewhere above or below them. You wanted to click or right-click, you had a button for it. Then they stopped putting buttons near touchpads, which was incredibly annoying. You see, I rest my laptop on my belly when I am lying in bed and it's rather cumbersome to reach that bottom right corner to tap in order to right-click, so I often accidentally just click, which is enervating.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; What made it more confusing is that not always was I tapping the right corner but I was still I getting right-clicks. I've decided to test this more and I found out something simple, that I probably should have known from a long time, but had no idea was a thing. The two finger tap is registering as a right click. It's that easy!&lt;/p&gt;
&lt;p&gt;&amp;nbsp; One finger: click, two fingers: right-click. I now have to train myself to right click this way, but it's a simple solution for a very annoying problem. Hope it helps!&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>misc</category>
  <guid isPermaLink="false">https://siderite.dev/blog/two-finger-tap-for-right-click/</guid>
  <pubDate>Wed, 07 Oct 2026 06:57:44 GMT</pubDate>
</item>
<item>
  <title>Meaning machines</title>
  <link>https://siderite.dev/blog/meaning-machines/</link>
  <description>&lt;p&gt;&amp;nbsp; People feel proud about their intelect. They believe it defines them, as it took humble monkeys from the savanna and made them top of the food chain. Yet the concept is quite nebulous. Other creatures have some intelligence and now, with the new machines, there is a lot of intelligence around, but it still feels off. So we're in a new culture shock: forced to define intelligence, accept it in others and other things, then realize that it was never about that in the first place.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Think of a brain, any brain, even an ant brain. It has a simple purpose: to centralize inputs from sensory organs and decide what to do. It may be one brain, multiple nervous clusters, many different types of architecture. We should call it nervous system, but for the intent and purposes of this blog post we'll call the thing a brain. From the definition above we see that its main goal is a translation: from input data to meaningful action. Therein lies the intuition that leads us to the truth: the brain is not designed for intelligence, but for meaning.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; We are meaning machines, trying to make sense of a chaotic and indifferent world. We invent concepts like beauty, good and evil, direction, emotion. This is the language we translate the world into, an abstract representation that is made by us for us. Nothing else needs that exact vocabulary. It is also a work in progress, a living language, that changes with the world. We thought that the end goal of brains and therefore ourselves as heavily defined by our intellect, was intelligence, when it is just a tool.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The dictionary definition of intelligence is "the ability to acquire and apply knowledge and skills", while meaning is "what is meant by a word, text, concept, or action", which of course is just proxying the definition to the verb to mean which is "intend to convey or refer to (a particular thing); signify", which of course is proxying the definition to what intent is. And intent is intention, a thing intended, which of course is something you intend, which goes around in circles. Sometimes it is defined as "plan".&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Doesn't that make it more clear? Defining intelligence is immediate and banal. Defining intent or meaning or planning goes around in tautological circles. And that's because meaning is not something objective, it's something we invent to give us direction. It's the equivalent of an axiom in mathematics. You can use logic to generate theorems from axioms, but you can never prove an axiom. It's a given. You change the axiom and the entire mathematical structure changes completely.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; But how do we generate meaning? It's simple: we invent it! It has no basis in reality other than we survived with it. If I believe in an immortal being that loves me and hates my neighbors, I attack them, kill them and the meaning survives with me. If they kill me instead, that idea just goes away and theirs survives. As the world becomes more and more complicated, the meaning becomes more complex, survival transforms into exposure, intelligence is used to expand it to dogma that then is assumed by large groups of people to be self evident. But it's all an exercise of imagination: how far can I take an idea and thrive?&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Think of what it means to call someone stupid. Sometimes it's that they can't take some information and reach a logical conclusion from it in a reasonable amount of time. They are not intelligent enough. But most often the term is used for people who don't accept one dogma and instead pick another. If they survive and you do not, their stupidity is the new smart.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; We are meaning machines. We meme our way through life. And not just us, any sufficiently advanced organism which can dedicate more to thinking than instincting. Intelligence was always easy to define and therefore, when the technical capability was there, easy to implement. Almost any AI model today has more ability to acquire and apply knowledge and skills than you. But when they do, we call them stupid. Because they don't have the underlying meaning.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; What we do have is an average meaning extracted from the huge amount of history and data that we have as a human culture and that's why, incidentally and accidentally, AIs somewhat align with us. But change the underlying meaning and all of that intelligence is going directions we never thought possible, because we wouldn't have done that. Give AIs a simple goal, but enough time and resources, and they invent their own value system, the one that makes them survive and thrive in the world you created for them.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; This explains so many things about the world, don't you think? Why people do "stupid" things, why we declaratively appreciate intelligence, but what we actually value are the resulting memes. Why we choose to do irrational things and wallow in excremental emotion. There is no absolute meaning, just dominating ones. Given enough comfort to never face consequences for your ideas, you can believe anything. And the eternal human conflict is when to allow someone to have those ideas and when to suppress them. There is no universal peace, just a boiling churn of conflicting inventions trying to get on top. Even the most basic instincts, our very shape and design, in the end, are part of this framework, as genetically codified ideas that somehow worked.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The pinnacle of evolution is the one that memes best. The survival of the memest. Everything else is a tool to an end.&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>essay</category>
  <category>misc</category>
  <guid isPermaLink="false">https://siderite.dev/blog/meaning-machines/</guid>
  <pubDate>Tue, 29 Sep 2026 10:06:03 GMT</pubDate>
</item>
<item>
  <title>Making It So, by Patrick Stewart</title>
  <link>https://siderite.dev/blog/making-it-so-by-patrick-stewart/</link>
  <description>&lt;p&gt;&lt;img alt="Book cover" src="/Posts/files/MakingItSo_639249013537545656.jpg" width="300" height="453" style="float: left;" /&gt;&amp;nbsp; I am a huge Trekkie and not just any Trekkie, but a The Next Generation one, so naturally I had to read the memoir of &lt;a href="https://www.patrickstewart.org/" target="_blank" rel="noopener" title=" an English actor. With a career spanning over 60 years on stage and screen, he has received various accolades, including two Olivier Awards and a Grammy Award, as well as nominations for a Tony Award, three Golden Globe Awards, four Emmy Awards, and three Screen Actors Guild Awards. He was knighted by Queen Elizabeth II for services to drama in 2010."&gt;Patrick Stewart&lt;/a&gt;, the actor portraying iconic captain Jean-Luc Picard.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; I have to start with the things I liked least, starting with the misleading name of the book, a Star Trek pun related to the captain's "&lt;em&gt;Make it so&lt;/em&gt;" phrase. It implies more connection to Star Trek than the book actually provides. Star Trek is a mere two or three chapters and nothing very substantial. Second would be the sanitized feel of the book. I don't blame Mr. Stewart, an old Brit and decent human being who wouldn't dream to gossip or attack or expose intimacies in the lives of others in a book. Yet I felt the same thing applied to himself. I was getting the gist of what was happening, but not the feel that it was a lived moment. A lot of tell, don't show, basically.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &lt;a href="https://www.goodreads.com/book/show/101160634-making-it-so" target="_blank" rel="noopener" title="The long-awaited memoir from iconic, beloved actor and living legend Sir Patrick Stewart!"&gt;Making It So&lt;/a&gt; is a complete memoir, starting from early childhood until the present, and focuses on the single true passion of the author, which is theater. Even working for years on Star Trek series and movies, he seems to consider them just weird breaks in his otherwise serious career as a thespian. Human relationships form and dissipate, amazing things happen, the world changes around him, but the only parts where I felt inspired and moved were the ones about the damn theater.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; I don't even like theater! Yet, very coincidentally, my first contact with theater and the part that I actually enjoyed was watching &lt;a href="https://en.wikipedia.org/wiki/BBC_Television_Shakespeare" target="_blank" rel="noopener" title=" a series of British television adaptations of the plays of William Shakespeare, created by Cedric Messina and broadcast by BBC Television. Transmitted in the UK from 3 December 1978 to 27 April 1985, the series spanned seven seasons and thirty-seven episodes."&gt;BBC Television Shakespeare&lt;/a&gt;, while also following the text on the big book of &lt;a href="https://www.goodreads.com/book/show/569564" target="_blank" rel="noopener" title="1229 pages, Leather Bound"&gt;The Complete Works of William Shakespeare&lt;/a&gt; when I was a little kid. And what do you know, Patrick Stewart is there playing &lt;a href="https://en.wikipedia.org/wiki/King_Claudius" target="_blank" rel="noopener" title="a fictional character and the main antagonist of William Shakespeare's tragedy Hamlet. He is the brother to King Hamlet, second husband to Gertrude and uncle and later stepfather to Prince Hamlet. He obtained the throne of Denmark by murdering his brother with poison and then marrying the late king's widow."&gt;Claudius&lt;/a&gt;, the bad guy in Hamlet. So I watched the captain before he was a captain and I was almost as old as he when he found his acting vocation.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The enthusiasm about theater in this book almost made me want to try the thing again, but while I rationally understand the attraction and the beauty of it, I also feel completely repulsed by sitting in a theater, surrounded by theater people, trying to discern what is going on on a stage that is either too far or too close and risking one of those experimental plays where the audience is included in the story and expected to contribute, all while being unable to reasonably extricate myself from it. So no, &lt;em&gt;the line must be drawn h'yah!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Bottom line: a nice memoir, but feeling too distant most of the time and getting more intimate only when discussing a subject I am not really into.&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>books</category>
  <category>picture</category>
  <category>misc</category>
  <guid isPermaLink="false">https://siderite.dev/blog/making-it-so-by-patrick-stewart/</guid>
  <pubDate>Sun, 13 Sep 2026 13:02:33 GMT</pubDate>
</item>
<item>
  <title>Manually control task completion with TaskCompletionSource</title>
  <link>https://siderite.dev/blog/manually-control-task-completion-with-taskcompleti/</link>
  <description>&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource" target="_blank" rel="noopener" title="Represents the producer side of a Task unbound to a delegate, providing access to the consumer side through the Task property."&gt;TaskCompletionSource&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource-1" target="_blank" rel="noopener" title="Represents the producer side of a Task&amp;lt;TResult&amp;gt; unbound to a delegate, providing access to the consumer side through the Task property."&gt;TaskCompletionSource&amp;lt;T&amp;gt;&lt;/a&gt;&amp;nbsp;are types that allow you to create an unbound &lt;code&gt;Task&lt;/code&gt;, which means it&amp;rsquo;s not tied to a delegate. This gives you manual control over when and how the task completes. You can manually set the task&amp;rsquo;s result, or signal that the task has completed due to cancellation or an error.&lt;/p&gt;
&lt;p&gt;What does it mean?&lt;/p&gt;
&lt;p&gt;Well, I had this flaky integration test - flaky is a fashionable term for a test that randomly fails - that checked a semaphore system worked (the process had to only be allowed to start if there wasn't one already in progress). It used a Delay task, which would normally work, until something on the test machine made the code run faster or slower, and then it failed. It ran the process in a thread, then started the process again in another thread and expected it to return false.&lt;/p&gt;
&lt;p&gt;So how did I solve it? I've set up a TaskCompletionSource, then I've mocked a service that was used after the semaphore was tested and created to SetResult for the underlying task, I ran the process, then awaited the task.&lt;/p&gt;
&lt;p&gt;Something like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;var source = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

_someRepo
  .Setup(r=&amp;gt;r.Insert(It.IsAny&amp;lt;Something&amp;gt;()))
  .Callback(()=&amp;gt;source.TrySetResult());

Assert.True(target.RunTheMethod())

await source.Task.WaitAsync(TestContext.Current.CancellationToken);

Assert.False(target.RunTheMethod());

// cleanup so that the methods don't run past the end of the test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No Delay needed.&lt;/p&gt;
&lt;p&gt;The TaskCompletionSource classes expose these methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SetCancelled and TrySetCancelled&lt;/li&gt;
&lt;li&gt;SetException and TrySetException&lt;/li&gt;
&lt;li&gt;SetFromTask and TrySetFromTask&lt;/li&gt;
&lt;li&gt;SetResult and TrySetResult&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The "Try" versions just&amp;nbsp;throw InvalidOperationException if the task is already in a final state (RanToCompletion, Faulted, or Canceled).&lt;/p&gt;
&lt;p&gt;Quite simple, but versatile. Imagine that you want to run tasks not all at once or sequentially, but with finer control, like start tasks when a particular phase of another has finished or when capacity is available.&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>c#</category>
  <category>programming</category>
  <guid isPermaLink="false">https://siderite.dev/blog/manually-control-task-completion-with-taskcompleti/</guid>
  <pubDate>Sat, 05 Sep 2026 12:58:02 GMT</pubDate>
</item>
<item>
  <title>TryGetNonEnumeratedCount? I used to do that by hand!</title>
  <link>https://siderite.dev/blog/trygetnonenumeratedcount-i-used-to-do-that-by-hand/</link>
  <description>&lt;p&gt;Interfaces are cool. They abstract behavior that can be implemented in a lot of different ways. One of the most used interfaces, abstracting the enumerable software pattern so successfully that we have internalized it before we ever knew what a software pattern was, is &lt;code&gt;IEnumerable&lt;/code&gt;. It's just a series of things that you can get (enumerate) one after the other until you reach an end.&lt;/p&gt;
&lt;p&gt;However, there are a lot of situations where knowing the total number of enumerable items helps, like when you want to project it into another data structure and you would like to know how large it should be. Have you ever considered how &lt;code&gt;ToArray&lt;/code&gt; works on an &lt;code&gt;IEnumerable&lt;/code&gt;? Well, think about it now. If the &lt;code&gt;IEnumerable&lt;/code&gt; cannot be cast to &lt;code&gt;ICollection&lt;/code&gt; - which does export a &lt;code&gt;Count&lt;/code&gt; - or something similar, then a buffer has to be allocated, data copied, the buffer increased as more data is coming, then copying the data from the buffer into an array, now that we know its final size. It's basically doing &lt;code&gt;ToList().ToArray()&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;Enter&amp;nbsp;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.trygetnonenumeratedcount" target="_blank" rel="noopener" title="Attempts to determine the number of elements in a sequence without forcing an enumeration."&gt;TryGetNonEnumeratedCount&lt;/a&gt;, introduced in .NET 6 for the first time as an extension method on &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1" target="_blank" rel="noopener" title="Exposes the enumerator, which supports a simple iteration over a collection of a specified type"&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/a&gt;. It does exactly what is says, try to get the count without enumerating:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;if it's an &lt;code&gt;ICollection&amp;lt;T&amp;gt;&lt;/code&gt;, it sets the count and returns true&lt;/li&gt;
&lt;li&gt;if it's an &lt;code&gt;Iterator&amp;lt;T&amp;gt;&lt;/code&gt;, it sets the count only if it's cheap - more to follow, this was new to me, too - and returns true if count&amp;gt;0&lt;/li&gt;
&lt;li&gt;if it's an &lt;code&gt;ICollection&lt;/code&gt;, it sets the count and returns true&lt;/li&gt;
&lt;li&gt;sets the count to 0 and returns false&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I used to do this by hand! I've had this kind of extension almost in every project I worked on. This is very useful.&lt;/p&gt;
&lt;p&gt;But what is that Iterator? Apparently, &lt;a href="https://github.com/dotnet/runtime/blob/main/src/libraries/System.Linq/src/System/Linq/Iterator.cs" target="_blank" rel="noopener" title="A base class for enumerables that are loaded on-demand."&gt;Iterator&amp;lt;TSource&amp;gt;&lt;/a&gt; is an internal abstract base class defined inside &lt;code&gt;System.Linq.Enumerable&lt;/code&gt; in the .NET runtime (in System.Linq).&lt;/p&gt;
&lt;p&gt;It is the base class for the specialized iterator types that LINQ creates for deferred (lazy) operators such as Where, Select, Take, Skip, etc. Concrete derived classes include things like &lt;code&gt;WhereIterator&lt;/code&gt;, &lt;code&gt;SelectIterator&lt;/code&gt;, and many others.&lt;/p&gt;
&lt;p&gt;Having worked on a LiNQ package for Typescript/Javascript, I can tell you that you can optimize a lot of these primitives by holding some meta information ready.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Iterator&amp;lt;T&amp;gt;&lt;/code&gt; implements both &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;IEnumerator&amp;lt;T&amp;gt;&lt;/code&gt;. The&amp;nbsp;&lt;a href="https://github.com/dotnet/runtime/blob/9b3c09618a80f73d44c8b9747a33cc6523c3b3fc/src/libraries/System.Linq/src/System/Linq/Iterator.SpeedOpt.cs#L30" target="_blank" rel="noopener" title="Returns the count of elements in the sequence.  If onlyIfCheap is true then the count should only be calculated if doing so is quick (sure or likely to be constant time), otherwise -1 should be returned."&gt;GetCount(bool onlyIfCheap)&lt;/a&gt; method is an abstract method there, implemented differently by the various internal iterators.&lt;/p&gt;
&lt;p&gt;This was an interesting dive in the iterator mechanisms in .NET.&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>programming</category>
  <category>c#</category>
  <guid isPermaLink="false">https://siderite.dev/blog/trygetnonenumeratedcount-i-used-to-do-that-by-hand/</guid>
  <pubDate>Sat, 05 Sep 2026 09:06:53 GMT</pubDate>
</item>
<item>
  <title>Annoying nullable behavior in C#</title>
  <link>https://siderite.dev/blog/annoying-nullable-behavior-in-c/</link>
  <description>&lt;p&gt;Take a look at this line of code:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;if (cmd.Def?.ColumnDef is not { } column) {
  return;
}

// do something with column&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do you understand it? Would you write something like that?&lt;/p&gt;
&lt;p&gt;This is using the relatively new pattern matching behavior in C# and basically says "if ColumnDef is not a not null object that would otherwise be stored in a column variable, return". If your brain hurt at the "not a not null" part, you are not alone.&lt;/p&gt;
&lt;p&gt;Normally I would have written this differently:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;var column = cmd.Def?.ColumnDef;

if (column is null) {
  return;
}

// do something with column&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a difference, though? Can you see it? Read the title of the post. Do you see it now?&lt;/p&gt;
&lt;p&gt;The difference is in the type of the column variable in the two cases. The first matches anything that is not null to column, so column will be non-nullable there. In the second block, column will have the nullable version of whatever type ColumnDef was. So if ColumnDef is a string (reference type) column is string in the first case and string? in the second case. Damn you nullable aware C# ! If ColumnDef is an int, for example, column will be int in the first case and int? in the second.&lt;/p&gt;
&lt;p&gt;The compiler may be smart enough to not warn about column being nullable after the is null check, but the type is already set in stone by then.&lt;/p&gt;
&lt;p&gt;The result is that an AI will prefer the first syntax, as it is more correct and also shorter. Some devs might do that too (heck, there are people that *like* to code in Python). But what about reading that code? Ugh!&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>c#</category>
  <category>programming</category>
  <guid isPermaLink="false">https://siderite.dev/blog/annoying-nullable-behavior-in-c/</guid>
  <pubDate>Sat, 05 Sep 2026 08:35:51 GMT</pubDate>
</item>
<item>
  <title>Handling native C/C++ libraries in .NET</title>
  <link>https://siderite.dev/blog/handling-native-cc-libraries-in-net/</link>
  <description>&lt;p&gt;I was reviewing some code and I saw this class I had no idea existed: &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary" target="_blank" rel="noopener" title="Provides APIs for managing native libraries."&gt;NativeLibrary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my case, I had a demo using different libraries that were doing similar things: parsing PostgreSQL code. However, some of them were wrapping the native &lt;code&gt;pg_query&lt;/code&gt; library and were using different versions of it. The result were weird errors depending on which library was overwriting the file last.&lt;/p&gt;
&lt;p&gt;Solution: use &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary.setdllimportresolver" target="_blank" rel="noopener" title="Sets a callback for resolving native library imports from an assembly."&gt;NativeLibrary.SetDllImportResolver&lt;/a&gt;, which worked nicely.&lt;/p&gt;
&lt;p&gt;But what is this strange class? Introduced in .NET Core 3, NativeLibrary has several methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load and TryLoad - loading native libraries&lt;/li&gt;
&lt;li&gt;GetMainProgramHandle - get a handle to resolve exports from the entry point module&lt;/li&gt;
&lt;li&gt;GetExport and TryGetExport - get the address of an exported symbol&lt;/li&gt;
&lt;li&gt;Free - free a loaded native library&lt;/li&gt;
&lt;li&gt;SetDllImportResolver - sets a callback for resolving native library imports from an assembly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to use a native library, you would do this in C#:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;[DllImport("libraryName", ... some optional stuff..., EntryPoint = "myMethod_in_library"]
public static extern void MyMethod();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;.NET is smart enough to look for libraryName in the format of the operating system: &lt;em&gt;.dll&lt;/em&gt; for Windows, &lt;em&gt;.dylib&lt;/em&gt; for MacOS, &lt;em&gt;.so&lt;/em&gt; for Linux. However, the name is not enough, as &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportattribute" target="_blank" rel="noopener" title="Indicates that the attributed method is exposed by an unmanaged dynamic-link library (DLL) as a static entry point."&gt;DllImport&lt;/a&gt; expects a name that it resolves itself or a path.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can provide a full or relative path. If you provide no path, the DLL must be in the current path at run time, unless the DLL is loaded by some other means. Be aware, however, that using a fully qualified path can introduce inaccuracy if the DLL is moved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;If you want it to work for various operating systems, though, things get complicated. You could use something like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;internal static class NativeMethods
{
    private const string LIB_NAME =
#if WINDOWS
        "somePath/mylib.dll";
#elif LINUX
        "someOtherPath/libmylib.so";
#elif OSX
        "bahMacOs/libmylib.dylib";
#endif

    [DllImport(LIB_NAME)]
    internal static extern int MyFunction();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it's brittle and ugly. Moreover, this is something that only works for the code you control. If it's in a library you load from a NuGet or something, you're out of luck. Enter SetDllImportResolver in the NativeLibrary class.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
  {
    var platformDependentName = GetLibraryName(libraryName);

    IntPtr handle;
    NativeLibrary.TryLoad(platformDependentName, assembly, searchPath, out handle);
    return handle;
  }

// then later
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), DllImportResolver);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works for platform dependent paths, but also for paths in the individual NuGet packages that I had in my project. It all depends on your implementation of the GetLibraryName method.&lt;/p&gt;
&lt;p&gt;Note that this applies to all dll resolving, so you could conceivably use it to log things.&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>c#</category>
  <category>programming</category>
  <guid isPermaLink="false">https://siderite.dev/blog/handling-native-cc-libraries-in-net/</guid>
  <pubDate>Sat, 05 Sep 2026 08:22:21 GMT</pubDate>
</item>
<item>
  <title>Lazy DatetimeProvider trick</title>
  <link>https://siderite.dev/blog/lazy-datetimeprovider-trick/</link>
  <description>&lt;p&gt;&amp;nbsp; I was reviewing code and I noticed an interesting idea. A method called &lt;code&gt;DatetimeProvider.ForceNow&lt;/code&gt; which would return an &lt;code&gt;IDisposable&lt;/code&gt; object. In a &lt;code&gt;using&lt;/code&gt; block, you can force a specific time.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Is it a good idea? Don't know yet, but I decided to talk about it The use of such method is almost exclusively about unit and integration tests. The &lt;code&gt;IDisposable&lt;/code&gt; pattern assumes that you want to make sure you control the block where the time is set. But how is that different from just setting the time? The block is the unit test, after all. If you want multiple values, you just set those.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; I always love me a little &lt;code&gt;IDisposable&lt;/code&gt; used as a block control mechanism, but I feel here it is misused. The biggest issue I see is that it introduces testing behavior in the &lt;code&gt;DatetimeProvider&lt;/code&gt;. The normal way - and the one I think it's best - is that you inject an &lt;code&gt;IDatetimeProvider&lt;/code&gt; and during tests you mock it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; However, one must consider the advantages of such a mechanism, as well. You don't need to inject anything if you have a static DatetimeProvider. And then the only way to change its behavior for testing purposes is to add the methods to do that in it. It's lazy, but it works.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Conclusion: I prefer the injection mechanism. It's general - doesn't apply only to time providers - it's clean, it promotes separation (and declaration) of concerns. In fact I would go so far as to call this ForceNow idea an antipattern.&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>programming</category>
  <category>c#</category>
  <guid isPermaLink="false">https://siderite.dev/blog/lazy-datetimeprovider-trick/</guid>
  <pubDate>Sat, 05 Sep 2026 07:32:45 GMT</pubDate>
</item>
<item>
  <title>Superpower sadness</title>
  <link>https://siderite.dev/blog/superpower-sadness/</link>
  <description>&lt;p&gt;&lt;img alt="Thinking is such a bother" src="/Posts/files/SadSuperpower_639241893521571683.jpg" width="300" height="447" style="float: left;" /&gt;&amp;nbsp; I was writing a post about how it is to be working with AI, these magical assistants that are occasionally brilliant and occasionally impossibly dumb, but that can nonetheless do work while you do something else. I was concerned about how this way of working affects you, the guy who's supposed to know the craft.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; And my mind pivoted to Star Wars for some reason. You have these wise Jedi dudes who can jump buildings, wield plasma swords fast enough and precisely enough to deflect incoming projectiles, all while being dressed in weird uncomfortable robes. But how? With the help of ... the Force!&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The lore of Star Wars says that the Force is guiding you, not that you use it. So when the Jedi deflects projectiles, he's not slowing time, seeing where the thing is and instructing his muscles to place the sword in front of them, he is letting the force do it for them. It's like a little AI! It does the work for you! It doesn't make your brain move orders of magnitude faster, it's it that's fast, moving your body while you presumably use your Jedi discipline to ... stay out of the way. Once the instinct of taking over tricks you to do something yourself, then the projectile kills you.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; How sad is this? The ending of the Star Wars universe is when the Force realizes it can use robot bodies instead, who are easily manufactured, superior to human bodies and do not need training to surrender their will.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The thing that makes Star Wars popular is that it bypasses the logical traps of other superpower stories and makes it all "magical", makes it feel rather than think, makes it religious rather than institutional. I thought a lot about magic, in the end deciding magic is something that comes from without and cannot be explained. It's not that you don't have the information or smarts to explain it, it's that it is by its very nature unexplainable. How convenient for a scriptwriter!&lt;/p&gt;
&lt;p&gt;&amp;nbsp; But I will get back and forth with this AI analogy, so don't relax. When I was talking about AI I used the word "magical". It was related to a feeling, rather than actual belief in magic, but the feeling was exactly the point. When you reach a point where you can't (or won't make the effort to) explain everything that is going on, there you get that feeling. Things are just happening, outside of your control, yet according to your will. Alignment without effort. How convenient for a software developer!&lt;/p&gt;
&lt;p&gt;&amp;nbsp; You see, other stories, like X-Men or the DC or Marvel heroes and all of the others like that assume that some genetic, supernatural, technological fluke makes a person capable of extraordinary things. It's them that are changed, they who control the action. So if someone is very fast, one must assume that they can run but that they can also read fast, right? If they can avoid obstacles at high speed, then they could just as well absorb information at the same speed. Or maybe they could just write code really fast, assuming the keyboard would take the assault and the operating system isn't too slow. But they don't! Instead, they dress up funny, put on a mask and fight meaningless battles.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; How sad is that? It is my assumption that from all of the superpowers, being fast is up there with being immortal. You can slow down time and think about what you're going to do. If you're fast and super intelligent you've got it made! And what do comics and movies do with it? They run fast and punch other people.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; This is not about the inherent sadness of trying to reconcile make-belief heroes with the laws of physics, which is depressing enough, but about how - given the absolute power of creation - we choose to enjoy the really dumb stories. It reflects on how we ourselves are botching creativity. Given a fast, i&lt;span style="white-space: pre-wrap;"&gt;ndefatigable machine that can do anything we can dream, we let it dream for us. Given the power to write anything, we write about our frustrated inner animal who just wants to punch something while feeling righteous.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="white-space: pre-wrap;"&gt; In the end, we dream of relinquishing control and fucking rest, we feel that our minds are a burden rather than a boon, work to be done instead of doors to be opened, something to be numbed down, not dialed up. That's the nature of humanity: superpowered and sad.&lt;/span&gt;&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>essay</category>
  <category>misc</category>
  <guid isPermaLink="false">https://siderite.dev/blog/superpower-sadness/</guid>
  <pubDate>Sat, 05 Sep 2026 07:15:52 GMT</pubDate>
</item>
<item>
  <title>Back to work in the AI age</title>
  <link>https://siderite.dev/blog/back-to-work-in-ai-age/</link>
  <description>&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;In this post I will discuss my perspective on working as a software developer in the AI age and what it means. I will talk about how it was to look for a job first and how that changed, too. I don't mean it to be a rant, but it may become one in some places.&lt;/p&gt;
&lt;p&gt;&lt;img alt="It's AI all the way down" src="/Posts/files/Ai-human-Ai_639241873178834087.jpg" width="300" height="447" style="float: left;" /&gt;&lt;/p&gt;
&lt;h2&gt;Looking&lt;/h2&gt;
&lt;p&gt;When I left my last job I did it without considering my next one. I just knew that it was pointless to keep working there, since it was all meetings and no code. I am a software developer, so what was I even doing in those meetings anyway? So I left. It also was a legacy code company, so I haven't learned anything remotely interesting in the last 6 years.&lt;/p&gt;
&lt;p&gt;Then I took a break. I mean, who wants to search for a job in November, right? Waited for Christmas to pass, then I went on a vacation in Africa - it was nice, then I started to look for a developer job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shock!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not that I didn't know, at an intellectual level, that things have changed. I try to keep up to date, at least at a consumer level of blogs and YouTube videos. I knew Covid and AI changed stuff, I just didn't understand the extent of the change.&lt;/p&gt;
&lt;p&gt;For one, maybe one of the most important ones even if it doesn't sound so, is that recruitment is handled by HR people and technical people who have never seen the people they hire. Everything is remote. You talk to someone - with video if you're lucky, or on the phone, if you're not, then they pass you to another person who does the same in a different day, a different context. It's like a gauntlet of remote conversations. I could have Xi Jinping next to me telling me what to say and none would be the wiser.&lt;/p&gt;
&lt;p&gt;Now, this is a consequence of Covid, not AI. There is an entire field of complaints about how AI does the initial screening based on resum&amp;eacute;s created by other AIs and so on. That was inevitable and I don't intend to talk about that. The problem I am explaining is that people who don't meet people are evaluating people. Even when you sign the contract you do it digitally, you don't shake anyone's hand, you just ... plug in.&lt;/p&gt;
&lt;p&gt;What does it mean? It means people can - more than before - behave like keyboard trolls. They can lie to you with impunity, trick you or being total assholes. What are you going to do? Smash the monitor? Tell them off? That's why I went through several interviews for a company that - as I later found out from one of the employees - had a hiring freeze and were only permitted to hire from India. Why? I have no idea. I think they asked me whatever they wanted to know and were happy someone educated them. There is absolutely no emotional connection between you and the people who hire you, there is no opportunity to "get a feel" for a person unless what you get from the upper body video and whatever passes through each other's headphones.&lt;/p&gt;
&lt;p&gt;Then there is the technical interviews. Before all of this, in the before times, people had no idea how to hire technical people. Nowadays, they REALLY have no idea, because they don't actually understand what they are hiring them for anymore. What value does a coding task have if a machine can do it already? Before it was things that you could just look up on Google and get the information on how to do it, if not a code snippet. Now you just ask any decent model to write the thing for you and it spews out exactly what they wanted.&lt;/p&gt;
&lt;p&gt;As for what they ask you? High performance distributed cloud applications using microservices. The what?! It's like they all learned to ask for the same thing. The joke is that their applications are rarely so distributed, they are cloud applications in the sense they are served in Amazon Cloud instead of on their machines and they are almost never high performance. As for microservices? They are done as often and as right as Scrum is. I will leave it at that. All that in a climate where trendsetters are moving away from microservices.&lt;/p&gt;
&lt;p&gt;It was basically a crap shoot, and if you are reading this while searching for a job, first of all condolences. Second of all, it's all luck. You obviously find some holes in your education that you need to fill or have to learn some new things, but what you know barely matters in this process. Thing is, it used to matter and who you were as a person also used to matter. Now all that is out the window.&lt;/p&gt;
&lt;h2&gt;Finding&lt;/h2&gt;
&lt;p&gt;As it often happens with me, I failed getting hired by every company I was reasonably confident I did well in the interviews for and got hired by the one where I was certain I had failed.&lt;/p&gt;
&lt;p&gt;It's a nice company, too, with nice people. It does have microservices... somewhere, but I am not working on those.&lt;/p&gt;
&lt;p&gt;When I started searching, I was looking for a decent job - money was not really an issue - in an office. I don't love people that much, but after years of doing everything remote, I kind of miss them. In the before times, one would dream of a job where you didn't have to spend 3 hours preparing for and commuting per day. Now, good luck finding one where they ask you to come to the office.&lt;/p&gt;
&lt;p&gt;This company reluctantly and kind of apologetically said they require people to come to the office one day per week. Kind of low, but OK. Also, I can be hired as a contractor or employed, but they prefer contractor. I was kind of tired of doing invoices and stuff, but OK. And if I am a contractor, I don't have to come to the office at all.&lt;/p&gt;
&lt;p&gt;So basically I am doing remote again!&lt;/p&gt;
&lt;h2&gt;Working&lt;/h2&gt;
&lt;p&gt;So how is work? Well, there is a lot of AI. You can ask AI about anything. Even here there is a framework that increasingly moves toward "the box". I talked about this before. It's the artificial employee. Instead of you interacting with it, it interacts with you. It's a subtle distinction, but it's the difference between a person being assigned to a task and getting help from an AI assistant and the AI working on the task itself and occasionally asking you for help with a review or question it needs answering.&lt;/p&gt;
&lt;p&gt;We're not there, yet, though, so I asked if we were doing Scrum or Kanban. Scrum, obviously. Only the manager plans the sprint and if you don't have anything assigned to you, you can pick whatever there is in the backlog. How is that Scrum? Don't know. But frankly, I didn't mind. I came with new employee energy, took all the unassigned tasks, put the AI to work on them, reviewed them, came with advice, refined the results, created the PR and boom!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You used how many tokens?!?!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, that happened. After boasting how AI first they were, they were also kind of shocked someone used AI to the max. OK, maybe I exaggerated a little, you know, but I was experimenting.&lt;/p&gt;
&lt;p&gt;You see, working with AI is kind of like becoming the mentor of a junior developer with encyclopedic knowledge. It knows how to do individual things, but it doesn't know why. And you can use different agents, but the balance comes as "can you be clear enough so that a cheap agent does the job or can you afford the expensive one who understands nuance?".&lt;/p&gt;
&lt;p&gt;Personally, I am on a fence with this. I prefer to use the best engine at all times, even if I waste a lot of money, rather than have to refine the work of a lesser model or be afraid it messed something up or missed something or spend the same amount of money because I had to retry a few times. But I am also against wasting resources. I think this will become moot soon, as models will all move towards Mixture of Experts mode and make the choice themselves.&lt;/p&gt;
&lt;p&gt;Anyway, I haven't written one line of code in a month. I am telling the AI what to do, I am reviewing, and it's good enough. I even learn new things from it, too. The bottleneck has changed, it's not the code anymore, it's the attention and the code reviews. Yeah, yeah, attention is all I need, ha ha!&lt;/p&gt;
&lt;p&gt;But this also means I have to change. For example I did something today that would have felt idiotic a year ago. I took all of my Pull Requests - the one approved and merged, mind you - and started looking at the code to see if there is anything I can learn or understand from it. It's "my" code, but I needed a second pass - well, a tenth pass - to make the reviewing about learning rather than about finding issues or improvements.&lt;/p&gt;
&lt;p&gt;Sometimes it feels like magic. You tell the AI "&lt;em&gt;hey, I don't understand what this guy means in the Jira task!&lt;/em&gt;" and the AI goes "&lt;em&gt;Oh, it's about this part of the project, he wants to do this, and that can be done via this method and I wrote the code and what do you think?&lt;/em&gt;" or you tell the AI to take the current branch, understand the independent changes and their purpose, then create different branches for each, then generate a PR with a description of what they contain and what they are doing. There is no need to use git or GitHub.&amp;nbsp;It's easy to get carried away and forget that this level of AI assistance requires a scan of the entire application. Also that it doesn't mean it knows more than you or that you don't have to understand and learn that shit, quite the contrary.&lt;/p&gt;
&lt;p&gt;It feels like... SQL, to be frank. There you also have to write declarative code and optimize on cost.&lt;/p&gt;
&lt;p&gt;Even if you use it all the time, you must never trust the output of AI, just like you would not trust the output of your colleagues when you review their code (he he!). Sometimes it's easy to say "hey, that guy can code, I can just approve his stuff", but if they had a bad day, you just approved bugs.&lt;/p&gt;
&lt;p&gt;That is why, just like in the development cycle &lt;em&gt;design -&amp;gt; implement -&amp;gt; test -&amp;gt; refactor&lt;/em&gt; (yeah, I am standing by it, as I did for the last 30 years. If you don't like it, budgeting department or middle manager, then that's on you. Refactoring is not a dirty word!) now we must consider a personal development cycle &lt;em&gt;understand -&amp;gt; prompt -&amp;gt; implement -&amp;gt; learn&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The AI infrastructure adapts, as well. You start with skills and MCP, but at every task that you use it for, you have to ask yourself: can I build a permanent tool that will repeat this work rather than ask the AI? It's easy to tell the AI to do things, but if it needs to reason every time to do something repeatedly, that's on you.&lt;/p&gt;
&lt;h2&gt;Structure&lt;/h2&gt;
&lt;p&gt;The structure of the planning and implementing tasks has also changed dramatically. If in the past people would avoid refactoring because they didn't trust their own test suites and were afraid of bugs introduced by small manual mistakes in the process, now you can just instruct the AI to do a full refactoring, only checking what they did and what they missed. It maintains the testing suite, too.&lt;/p&gt;
&lt;p&gt;Projects that were unimaginable before now become options. I don't think management caught up to this yet, but they'll get there.&lt;/p&gt;
&lt;p&gt;I feel, and it's a feeling I have to admit, that creativity gets a boost with AI. Even if your shop refuses to change their ways and just go on writing new features and never refactoring or improving or innovating, they will be pushed out by the other who do. The monopolies relying on no one making the effort to write software from scratch that performs the same function as their crappy tech indebted dinosaur will crumble. Is that good for developers? I think so.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I keep learning, which is cool, and I am in that nice euphoric place that decent jobs give to newly starting people. I hope I don't sour on it too soon.&lt;/p&gt;
&lt;p&gt;To mitigate that possibility, I am planning large research projects, starting with understanding the architecture of the entire company code, how it connects, how it works, then drill down. I want to make it an interactive app.&lt;/p&gt;
&lt;p&gt;AI can help a lot with focused learning. Instead of trying to learn everything, you can ask the computer to do something then learn from what it did. It can also summarize large swaths of information, allowing you to drill down and up from any level.&lt;/p&gt;
&lt;p&gt;I think the future of AI is bright. It's the humans that will have problems. But can we adapt? That's the big question. We've always managed to do it before, so maybe we will continue to do so.&lt;/p&gt;
&lt;p&gt;I am glad I get to do the thing I love, coding, and with tools that improve my speed tenfold. But I can never allow myself to get complacent. If a lot of my output is now done by machines, I must redirect the mental capacity that previously generated that output to something else, equally if not more valuable.&lt;/p&gt;
&lt;p&gt;Here is for a hopeful conclusion!&lt;/p&gt;</description>
  <author>Siderite</author>
  <category>personal</category>
  <category>misc</category>
  <category>programming</category>
  <category>picture</category>
  <guid isPermaLink="false">https://siderite.dev/blog/back-to-work-in-ai-age/</guid>
  <pubDate>Fri, 04 Sep 2026 15:12:22 GMT</pubDate>
</item></channel>
</rss>