<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Home on Luatic's Bloarg</title><link>https://luatic.dev/</link><description>Recent content in Home on Luatic's Bloarg</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Wed, 18 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://luatic.dev/index.xml" rel="self" type="application/rss+xml"/><item><title>On string concatenation</title><link>https://luatic.dev/posts/str-concat/</link><pubDate>Wed, 18 Feb 2026 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/str-concat/</guid><description>&lt;p&gt;When building strings, perhaps the first operation programmers learn,
one of the few operators which tend to be introduced early on, is &lt;em&gt;string concatenation&lt;/em&gt;.
A simple, straightforward way to build strings.&lt;/p&gt;
&lt;p&gt;In modern programming languages, strings are typically &lt;em&gt;immutable&lt;/em&gt;, to avoid many of the surprises that
may occur with mutable strings (and mutability in general).
An advantage of this is that it enables string interning, which saves memory if many strings are duplicated
and makes string comparisons cheap constant time pointer comparisons.&lt;/p&gt;</description></item><item><title>Python's variable scoping sucks</title><link>https://luatic.dev/posts/python-var-scoping/</link><pubDate>Sun, 08 Feb 2026 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/python-var-scoping/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;[&amp;hellip;] could you explain Python&amp;rsquo;s variable scoping rules?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Well, it&amp;rsquo;s very easy. They are local to arbitrarily defined block[s] unless they are not.
In such case they are available only in otherwise arbitrarily defined blocks.&amp;rdquo;&lt;br&gt;
&amp;ndash; Aaa, on the Lua discord&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How precisely it sucks is best demonstrated by example.
I hope to convince you that maybe there are some aspects to Python
that don&amp;rsquo;t exactly make it the friendliest language for a beginner to get into.
A seasoned programmer will be able to cope with this, but might still be surprised about an edge case or two.&lt;/p&gt;</description></item><item><title>About</title><link>https://luatic.dev/about/</link><pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate><guid>https://luatic.dev/about/</guid><description>&lt;h2 id="hello-there"&gt;Hello there!&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m Lars, a 21 year old computing nerd from Germany.
You might also know me by one of a couple nicknames. &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;
In the last couple years, I have mostly been going by &amp;ldquo;luatic&amp;rdquo; online.&lt;/p&gt;
&lt;h3 id="programming"&gt;Programming&lt;/h3&gt;
&lt;p&gt;A lot of my life revolves around programming.&lt;/p&gt;
&lt;p&gt;Due to a lucky coincidence, I started to learn programming relatively early,
by making little 2d video games in Python.
Since then, programming and related activities have become the thing I spend most of my time on.
I&amp;rsquo;ve now programmed for well over a decade.&lt;/p&gt;</description></item><item><title>On ID generation</title><link>https://luatic.dev/posts/idgen/</link><pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/idgen/</guid><description>&lt;p&gt;It happens very often in software that we have some kind of object
and we want to give it some kind of unique identifier, called &amp;ldquo;ID&amp;rdquo; for short.
It&amp;rsquo;s important that you get this right, or at least not horribly wrong.
So here&amp;rsquo;s what you &lt;em&gt;can&lt;/em&gt; do.&lt;/p&gt;
&lt;h2 id="use-the-object-itself-as-id"&gt;Use the object itself as ID&lt;/h2&gt;
&lt;p&gt;Why redo what the memory allocator already did: Allocate, for each unique object, a unique memory address. &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;</description></item><item><title>On cheating</title><link>https://luatic.dev/posts/2025-07-25-cheating/</link><pubDate>Fri, 25 Jul 2025 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2025-07-25-cheating/</guid><description>&lt;p&gt;Cheating is a problem as old as time.&lt;/p&gt;
&lt;p&gt;The theoretical prevention is simple to state vaguely:
&amp;ldquo;Harden&amp;rdquo; the protocol. Interactions need to be clearly defined.
Players are only told what they need to know;
they are restricted to legal actions as defined by the game rules.&lt;/p&gt;
&lt;p&gt;This is relatively easy especially for well-defined simple board games, say, chess.
The server can easily reject illegal moves; both players know the entire board state at all time.
Yet the problem of cheating is not at all solved:
Chess engines have outperformed even the very best human players since the days Kasparov lost to Deep Blue.
Today any ordinary computer can obliterate a chess grandmaster.
This brings us to our first fundamental problem:&lt;/p&gt;</description></item><item><title>Lua misconceptions</title><link>https://luatic.dev/posts/lua-misconceptions/</link><pubDate>Sat, 12 Apr 2025 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/lua-misconceptions/</guid><description>&lt;p&gt;This is a collection of various Lua misconceptions I have seen over the years.&lt;/p&gt;
&lt;p&gt;To clarify matters regarding language semantics, we refer to the manual guarantee;
the relevant guarantees haven&amp;rsquo;t changed from version 5.1 through 5.4.&lt;/p&gt;
&lt;p&gt;Unfortunately the reference manual mostly refrains from statements concerning performance,
which plenty of misconceptions revolve around.
To discuss performance characteristics, we look at the two most prevalent implementations,
the reference implementation, &lt;a href="https://www.lua.org/"&gt;PUC Lua&lt;/a&gt;,
and &lt;a href="https://luajit.org"&gt;LuaJIT&lt;/a&gt;, renowned for its speed.&lt;/p&gt;</description></item><item><title>Sticks and stones won't break my bones</title><link>https://luatic.dev/posts/2025-02-20-breaking-bones/</link><pubDate>Thu, 20 Feb 2025 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2025-02-20-breaking-bones/</guid><description>&lt;p&gt;&amp;hellip; but &lt;a href="https://irrlicht.sourceforge.net/"&gt;Irrlicht&lt;/a&gt; will.&lt;/p&gt;
&lt;p&gt;This software horror tale has all you expect: There&amp;rsquo;s an old legacy C++
codebase, a familiar culprit and ultimately, a bugfix followed by
workarounds to put the bug back in to some extent.&lt;/p&gt;
&lt;h2 id="the-beginning"&gt;The beginning&lt;/h2&gt;
&lt;p&gt;Many years ago &lt;a href="https://luanti.org"&gt;Luanti&lt;/a&gt; (then called Minetest)
suffered from a major bug: Skeletal keyframe-based animation and bone
overrides could not be used together.&lt;/p&gt;
&lt;p&gt;As soon as you overrode &lt;em&gt;any&lt;/em&gt; bone, the entire model would cease
animating.&lt;/p&gt;</description></item><item><title>Object-oriented programming (in Lua)</title><link>https://luatic.dev/posts/2024-04-07-oop-in-lua/</link><pubDate>Sun, 07 Apr 2024 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2024-04-07-oop-in-lua/</guid><description>&lt;p&gt;Time and time again, programming newcomers, through no fault of their own,
are introduced to object-oriented programming (OOP) in languages that
lead to a significant obstruction of the core principles of OOP.&lt;/p&gt;
&lt;p&gt;Additionally, Lua newcomers have trouble understanding how to implement OOP in Lua,
often resorting to replicating &amp;ldquo;patterns&amp;rdquo; found on the internet,
leading to a very fuzzy notion of how it works
and resulting in confusion when this does not behave as expected.&lt;/p&gt;</description></item><item><title>The case for closures (in Lua)</title><link>https://luatic.dev/posts/2023-09-16-the-case-for-closures-in-lua/</link><pubDate>Sat, 16 Sep 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-09-16-the-case-for-closures-in-lua/</guid><description>&lt;p&gt;I have recently been criticized for my use of &amp;ldquo;nested&amp;rdquo; functions in Lua;
the criticism revolved mostly about presumed performance problems (due to the cost of closure creation)
and the claim that the usage of nested functions was &amp;ldquo;unnecessary&amp;rdquo; from a code quality standpoint.
Here is my attempt at a thorough analysis, making a case for closures and more specifically the usage of &amp;ldquo;nested&amp;rdquo; functions in Lua.&lt;/p&gt;
&lt;h2 id="functional-programming"&gt;Functional Programming&lt;/h2&gt;
&lt;p&gt;(Lua) closures alone suffice as Lambda Calculus - that is, closures paired with function application are Turing-complete.
With higher-order functions, functional programming - fundamentally based on Lambda Calculus - is fully possible in Lua.
Even just some very basic higher-order functions like &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt; or &lt;code&gt;fold&lt;/code&gt; can already be very useful abstractions for working with iterators -
most often implemented as closures, unless it is possible to efficiently wrap up their state in a single control variable + invariant state (as with &lt;code&gt;ipairs&lt;/code&gt; and &lt;code&gt;pairs&lt;/code&gt;) -
but of course aren&amp;rsquo;t inexpensive in Lua;
in much less dynamic languages like Rust, closures can often even be used as zero-cost abstractions.&lt;/p&gt;</description></item><item><title>Syntactic Sugar in Lua</title><link>https://luatic.dev/posts/2023-07-26-lua-syntactic-sugar/</link><pubDate>Wed, 26 Jul 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-07-26-lua-syntactic-sugar/</guid><description>&lt;p&gt;Lua is a very minimalistic language.
This doesn&amp;rsquo;t mean that it lacks syntactic sugar though;
plenty of constructs native to other languages are &amp;ldquo;emulated&amp;rdquo;
using more powerful constructs in Lua and thus need sugar
for Lua to look &amp;amp; feel nice - Lua has more syntactic sugar than you may realize!&lt;/p&gt;
&lt;h2 id="table-indexing"&gt;Table Indexing&lt;/h2&gt;
&lt;p&gt;Lua&amp;rsquo;s one-in-all datastructure is the &lt;em&gt;table&lt;/em&gt;, which is array and hash map in one.&lt;/p&gt;
&lt;p&gt;Since tables are used to implement data structures including &amp;ldquo;instances&amp;rdquo; of &amp;ldquo;classes&amp;rdquo;,
accessing &amp;ldquo;fields&amp;rdquo; must be convenient. Lua thus provides the &lt;code&gt;.&lt;/code&gt; indexing sugar:&lt;/p&gt;</description></item><item><title>On Quicksort</title><link>https://luatic.dev/posts/2023-07-15-on-quicksort/</link><pubDate>Sat, 15 Jul 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-07-15-on-quicksort/</guid><description>&lt;p&gt;Quicksort is a rather popular sorting algorithm implemented by most standard libraries.
Yet it has its shortcomings and special care needs to be taken to implement it properly.
It is not uncommon for standard libraries to use a mix of sorting algorithms for the best performance,
often using asymptotically suboptimal but simple algorithms like insertion sort once the problem has been sufficiently reduced
and falling back to asymptotically reliable algorithms like heapsort if quicksort doesn&amp;rsquo;t progress fast enough
(see for example Go&amp;rsquo;s &lt;a href="https://cs.opensource.google/go/go/+/master:src/sort/zsortfunc.go"&gt;mix of sorting algorithms under the hood&lt;/a&gt;).&lt;/p&gt;</description></item><item><title>Approximating π</title><link>https://luatic.dev/posts/2023-06-25-approximating-pi/</link><pubDate>Mon, 26 Jun 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-06-25-approximating-pi/</guid><description>&lt;p&gt;Toying with a few intuitive (and less intuitive but more efficient) ways to approximate \(\pi\).&lt;/p&gt;
&lt;h2 id="throwing-darts"&gt;Throwing darts&lt;/h2&gt;
&lt;p&gt;This is perhaps the simplest method I&amp;rsquo;ve encountered yet -
simple enough that you could teach it to absolute beginners
once you&amp;rsquo;ve introduced &lt;code&gt;math.random&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Based on the formula \(A = \pi r^2\) for the area A of a circle,
\(\pi\) can be defined as the ratio of a circle with radius \(r\)
to a square with both sides of length \(r\).&lt;/p&gt;</description></item><item><title>Backporting _ENV to Lua 5.1</title><link>https://luatic.dev/posts/2023-03-01-backporting-env-to-lua51/</link><pubDate>Wed, 01 Mar 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-03-01-backporting-env-to-lua51/</guid><description>&lt;p&gt;Lua 5.2 has replaced &lt;code&gt;setfenv(stacklevel_or_func, env)&lt;/code&gt; and &lt;code&gt;getfenv(stacklevel_or_func)&lt;/code&gt; with assignments to / accesses of the implicit &lt;code&gt;_ENV&lt;/code&gt; upvalue of each function:&lt;/p&gt;
&lt;p&gt;The statement &lt;code&gt;_ENV = env&lt;/code&gt; in a function is equivalent to &lt;code&gt;setfenv(1, env)&lt;/code&gt;, changing the current function environment to &lt;code&gt;env&lt;/code&gt;, and the expression &lt;code&gt;_ENV&lt;/code&gt; is equivalent to &lt;code&gt;getfenv(1)&lt;/code&gt;, getting the current function environment.&lt;/p&gt;
&lt;p&gt;By using &lt;code&gt;setfenv&lt;/code&gt; and &lt;code&gt;debug.sethook&lt;/code&gt;, this &amp;ldquo;feature&amp;rdquo; can be (superficially) added to all Lua functions: Whenever a function is called, the environment is hooked using a proxy table to provide special treatment for assigning to (&lt;code&gt;__newindex&lt;/code&gt;) or getting (&lt;code&gt;__index&lt;/code&gt;) &lt;code&gt;_ENV&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>On the misconception that const is recursive</title><link>https://luatic.dev/posts/2023-03-01-const-misconception/</link><pubDate>Wed, 01 Mar 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-03-01-const-misconception/</guid><description>&lt;p&gt;The &lt;code&gt;const&lt;/code&gt; keyword applies only to variables - not to the contents of variables.
The following is valid JavaScript (Java&amp;rsquo;s &lt;code&gt;final&lt;/code&gt; or Lua&amp;rsquo;s &lt;code&gt;local &amp;lt;const&amp;gt;&lt;/code&gt; are analogeous):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;const&lt;/span&gt; p = {x: 1, y: 2};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p.x = 3;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;since &lt;code&gt;p&lt;/code&gt; is not assigned to.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;const&lt;/span&gt; p = {x: 1, y: 2};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p = {x: 42, y: 33};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;would be illegal however.&lt;/p&gt;
&lt;p&gt;JavaScript provides &lt;code&gt;Object.freeze&lt;/code&gt; to make an object immutable (which again only is shallow though!):&lt;/p&gt;</description></item><item><title>Lua Quines</title><link>https://luatic.dev/posts/2023-02-25-lua-quines/</link><pubDate>Sat, 25 Feb 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-02-25-lua-quines/</guid><description>&lt;h2 id="cheating-quines"&gt;Cheating Quines&lt;/h2&gt;
&lt;h3 id="the-trivial-quine"&gt;The Trivial Quine&lt;/h3&gt;
&lt;p&gt;The empty string `` technically is a quine in most scripting languages since it outputs itself - nothing, the empty string - when run.&lt;/p&gt;
&lt;h3 id="a-debug-quine"&gt;A Debug Quine&lt;/h3&gt;
&lt;p&gt;Reads its own source. May not work if the source file has been moved.&lt;/p&gt;
&lt;p&gt;Also works if the quine is not loaded from a file
(i.e. loaded from a string), as long as no &amp;ldquo;name&amp;rdquo; has been passed
(doesn&amp;rsquo;t work in the Lua REPL, since there the source will be &lt;code&gt;=stdin&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>How RegEx implementations suck</title><link>https://luatic.dev/posts/2023-02-21-how-regex-impls-suck/</link><pubDate>Tue, 21 Feb 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-02-21-how-regex-impls-suck/</guid><description>&lt;p&gt;Regular languages are a powerful and beautiful formal tool to validate or parse strings.&lt;/p&gt;
&lt;p&gt;Yet &amp;ldquo;regular&amp;rdquo; expression (&amp;ldquo;RegEx[p]&amp;rdquo;) implementations are often despised by programmers for a couple (good) reasons:&lt;/p&gt;
&lt;h2 id="more-than-just-regex"&gt;More than just RegEx&lt;/h2&gt;
&lt;p&gt;Part of what keeps regular languages and the theory surrounding them simple
is their limitations: Regular languages can&amp;rsquo;t count infinitely;
they can&amp;rsquo;t match brackets or keep track of indentation.&lt;/p&gt;
&lt;p&gt;This led to hacky extensions to RegEx to add such &amp;ldquo;features&amp;rdquo; like backreferences
(which is even more powerful than counting) or bracket matching, extending the expressiveness of RegEx
beyond that of regular grammars, making regular expressions nonregular and often matching context-free grammars (CFGs) or - even worse - context-sensitive grammars,
which in turn 99% of the time is backed by a horribly inefficient implementation.&lt;/p&gt;</description></item><item><title>The coroutine stack</title><link>https://luatic.dev/posts/2023-02-21-the-coroutine-stack/</link><pubDate>Tue, 21 Feb 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-02-21-the-coroutine-stack/</guid><description>&lt;p&gt;A coroutine + callstack-based stack of varargs in pure Lua.
Inspired by &lt;a href="https://twitter.com/ImogenBits/status/1325424621286518784"&gt;this tweet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note: Currently, for the sake of simplicity, only a single stack is implemented.
By parameterizing each function in terms of the &lt;code&gt;stack&lt;/code&gt;, multiple stacks
could be implemented, but this is not for practical purposes
(in practice, you should usually use tables paired with &lt;code&gt;table.insert&lt;/code&gt;
and &lt;code&gt;table.remove&lt;/code&gt; instead, unless your problem lends itself well
to a recursive solution; keep stack overflows in mind though).&lt;/p&gt;</description></item><item><title>Why some things are bound to be janky in Luanti</title><link>https://luatic.dev/posts/2023-02-21-luanti-rant/</link><pubDate>Tue, 21 Feb 2023 00:00:00 +0000</pubDate><guid>https://luatic.dev/posts/2023-02-21-luanti-rant/</guid><description>&lt;p&gt;So, you want(ed) to write a bow mod. It&amp;rsquo;s time to confront you with the harsh reality of just how limited the Luanti engine is.&lt;/p&gt;
&lt;p&gt;Disclaimer: Some concepts for the &amp;ldquo;ideal bow mod&amp;rdquo; detailed below are not feasible to be implemented and are mostly of theoretical nature.&lt;/p&gt;
&lt;h2 id="visuals"&gt;Visuals&lt;/h2&gt;
&lt;p&gt;You probably don&amp;rsquo;t want your arrows to be a bunch of sprites, so your only option
is to use a heavyweight entity with a mesh visual.
Spamming arrows may drag FPS down (due to lack of batching - one drawcall is issued for each entity);
additionally, each arrow will generate significant network traffic and increase the time
required to find any entities since all entities reside in the same global set to be
searched linearly for each and every query (see also poor collision performance and attempts to use spatial indexing).&lt;/p&gt;</description></item></channel></rss>