<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hacker News: sparkie</title><link>https://news.ycombinator.com/user?id=sparkie</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Tue, 07 Apr 2026 00:46:35 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=sparkie" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by sparkie in "Endian wars and anti-portability: this again?"]]></title><description><![CDATA[
<p>Reminder that the computer's endianness shouldn't matter. You should only care about the endianness of the streams your reading from and writing to.<p><a href="https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html" rel="nofollow">https://commandcenter.blogspot.com/2012/04/byte-order-fallac...</a></p>
]]></description><pubDate>Mon, 06 Apr 2026 05:07:40 +0000</pubDate><link>https://news.ycombinator.com/item?id=47657200</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47657200</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47657200</guid></item><item><title><![CDATA[New comment by sparkie in "Midicrossword"]]></title><description><![CDATA[
<p>It double types each letter I type. Quite annoying.</p>
]]></description><pubDate>Thu, 02 Apr 2026 09:03:56 +0000</pubDate><link>https://news.ycombinator.com/item?id=47611834</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47611834</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47611834</guid></item><item><title><![CDATA[New comment by sparkie in "A case against currying"]]></title><description><![CDATA[
<p>S-expressions are more like the tupled argument form, but better.<p><pre><code>    (f x y z)
</code></pre>
Is equivalent to:<p><pre><code>    (f . (x . (y . (z . ())))
</code></pre>
Every function takes one argument - a list.<p>Lists make partial application simpler than with tuples (at least Haskell style tuples), because we don't need to define a new form for each N-sized tuple. Eg, in Haskell you'd need:<p><pre><code>    partial2 : (((a, b) -> z), a) -> (b -> z)
    partial3 : (((a, b, c) -> z), a) -> ((b, c) -> z)
    partial4 : (((a, b, c, d) -> z), a) -> ((b, c, d) -> z)
    ...
</code></pre>
With S-expressions, we can just define a partial application which takes the first argument (the car of the original parameter list) and returns a new function taking a variadic number of arguments (the cdr of the original parameter list). Eg, using a Kernel operative:<p><pre><code>    ($define! $partial
        ($vau (f first) env
            ($lambda rest
                (eval (list* f first rest) env))))

    ($define! f ($lambda (x y z) (+ x y z)))
    (f 3 2 1)
    => 6
    
    ($define! g ($partial f 3))
    (g 2 1)
    => 6
    
    ($define! h ($partial g 2))
    (h 1)
    => 6

    ($define! i ($partial h 1))
    (i)
    => 6
</code></pre>
We could perhaps achieve the equivalent in Haskell explicitly with a multi-parameter typeclass and a functional dependency. Something like:<p><pre><code>    class Partial full first rest | full first -> rest where
        partial :: (full -> z, first) -> (rest -> z)
        
    instance Partial ((a,b)) a b where
        partial (f, a) = \b -> f (a, b)
        
    instance Partial ((a, b, c)) a ((b, c)) where
        partial (f, a) = \(b, c) -> f (a, b, c)
        
    instance Partial ((a, b, c, d)) a ((b, c, d)) where
        partial (f, a) = \(b, c, d) -> f (a, b, c, d)

    ...</code></pre></p>
]]></description><pubDate>Mon, 23 Mar 2026 01:15:22 +0000</pubDate><link>https://news.ycombinator.com/item?id=47484289</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47484289</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47484289</guid></item><item><title><![CDATA[New comment by sparkie in "Show HN: GDSL – 800 line kernel: Lisp subset in 500, C subset in 1300"]]></title><description><![CDATA[
<p>They have dozens of passes for semantic analysis and optimization, often configurable via flags, and they target dozens of different architectures.</p>
]]></description><pubDate>Mon, 16 Mar 2026 11:30:51 +0000</pubDate><link>https://news.ycombinator.com/item?id=47397638</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47397638</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47397638</guid></item><item><title><![CDATA[New comment by sparkie in "XML Is a Cheap DSL"]]></title><description><![CDATA[
<p>I'm not an academic and have extensive experience with parsing.<p>But for whataver reason, VPAs have slipped under my radar until very recently - I only discovered them a few weeks ago and have been quite fascinated. Have been reading a lot (the citations I've given are some of my recent reading), and am currently working on a visibly pushdown parser generator. I'm more interested in the practical use than the acamedic side, but there's little resources besides academic papers for me to go off.<p>Thought it might be interesting to share in case others like me have missed out on VPAs.</p>
]]></description><pubDate>Sat, 14 Mar 2026 20:40:13 +0000</pubDate><link>https://news.ycombinator.com/item?id=47380939</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47380939</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47380939</guid></item><item><title><![CDATA[New comment by sparkie in "XML is a cheap DSL"]]></title><description><![CDATA[
<p>(Properly formatted) XML can be parsed, and streamed, by a visibly-pushdown automaton[1][2].<p>"Visibly Pushdown Expressions"[3] can simplify parsing with a terse syntax styled after regular expressions, and there's an extension to SQL which can query XML documents using VPAs[4].<p>JSON can also be parsed and validated with visibly pushdown automata. There's an interesting project[5] which aims to automatically produce a VPA from a JSON-schema to validate documents.<p>In theory these should be able outperform parsers based on deterministic pushdown automata (ie, (LA)LR parsers), but they're less widely used and understood, as they're much newer than the conventional parsing techniques and absent from the popular literature (Dragon Book, EAC etc).<p>[1]:<a href="https://madhu.cs.illinois.edu/www07.pdf" rel="nofollow">https://madhu.cs.illinois.edu/www07.pdf</a><p>[2]:<a href="https://www.cis.upenn.edu/~alur/Cav14.pdf" rel="nofollow">https://www.cis.upenn.edu/~alur/Cav14.pdf</a><p>[4]:<a href="https://web.cs.ucla.edu/~zaniolo/papers/002_R13.pdf" rel="nofollow">https://web.cs.ucla.edu/~zaniolo/papers/002_R13.pdf</a><p>[3]:<a href="https://homes.cs.aau.dk/~srba/courses/MCS-07/vpe.pdf" rel="nofollow">https://homes.cs.aau.dk/~srba/courses/MCS-07/vpe.pdf</a><p>[5]:<a href="https://www.gaetanstaquet.com/ValidatingJSONDocumentsWithLearnedVPA/" rel="nofollow">https://www.gaetanstaquet.com/ValidatingJSONDocumentsWithLea...</a></p>
]]></description><pubDate>Sat, 14 Mar 2026 19:52:02 +0000</pubDate><link>https://news.ycombinator.com/item?id=47380472</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47380472</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47380472</guid></item><item><title><![CDATA[New comment by sparkie in "PC processors entered the Gigahertz era today in the year 2000 with AMD's Athlon"]]></title><description><![CDATA[
<p>That's not going to happen, but there's alternative research such as [1] where we get rid of the clock and use self-timed circuits.<p>[1]:<a href="https://arc.cecs.pdx.edu/" rel="nofollow">https://arc.cecs.pdx.edu/</a></p>
]]></description><pubDate>Sat, 07 Mar 2026 17:16:54 +0000</pubDate><link>https://news.ycombinator.com/item?id=47289488</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47289488</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47289488</guid></item><item><title><![CDATA[New comment by sparkie in "Show HN: Tanstaafl – Pay-to-inbox email on Bitcoin Lightning"]]></title><description><![CDATA[
<p>Advertisers will still pay, but they would need to adjust their strategy to target their ads more carefully to those who are likely to result in sales.<p>For legitimate senders, the attached fee would end up being spent by the receiver to send a reply, like a "refund", so it ends up zero-sum.<p>But for spammers it becomes an expensive option. Nobody is going to reply to the spam to "refund" their fee.</p>
]]></description><pubDate>Sat, 07 Mar 2026 12:09:06 +0000</pubDate><link>https://news.ycombinator.com/item?id=47286907</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47286907</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47286907</guid></item><item><title><![CDATA[New comment by sparkie in "Osaka: Kansai Airport proud to have never lost single piece of luggage (2024)"]]></title><description><![CDATA[
<p>My luggage was missing when I landed at KIX.<p>But it wasn't the airport's fault - my luggage was still in Amsterdam.<p>Arrived <24 hours later and they delivered it to my hotel in Osaka.</p>
]]></description><pubDate>Tue, 24 Feb 2026 17:32:52 +0000</pubDate><link>https://news.ycombinator.com/item?id=47139939</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47139939</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47139939</guid></item><item><title><![CDATA[New comment by sparkie in "Defer available in gcc and clang"]]></title><description><![CDATA[
<p>While the macro version doesn't permit this, if it were built-in syntax (as in C#) we can write something like:<p><pre><code>    using (auto res1 = acquire1(); free(res1))
    using (auto res2 = acquire2(); free(res2))
    using (auto res3 = acquire3(); free(res3)) 
    {
        // use resources here
    } 
    // free(res3); free(res2); free(res1); called in that order.
</code></pre>
The argument for this approach is it is structural. `defer` statements are not structural control flow: They're `goto` or `comefrom` in disguise.<p>---<p>Even if we didn't want to introduce new scope, we could have something like F#'s `use`[1], which makes the resource available until the end of the scope it was introduced.<p><pre><code>    use auto res1 = acquire1() defer { free(res1); };
    use auto res2 = acquire2() defer { free(res2); };
    use auto res3 = acquire3() defer { free(res3); };
    // use resources here

</code></pre>
In either case (using or use-defer), the acquisition and release are coupled together in the code. With `defer` statements they're scattered as separate statements. The main argument <i>for</i> `defer` is to keep the acquisition and release of resources together in code, but defer statements fail at doing that.<p>[1]:<a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/resource-management-the-use-keyword#use-binding" rel="nofollow">https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...</a></p>
]]></description><pubDate>Fri, 20 Feb 2026 16:42:44 +0000</pubDate><link>https://news.ycombinator.com/item?id=47090318</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47090318</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47090318</guid></item><item><title><![CDATA[New comment by sparkie in "Defer available in gcc and clang"]]></title><description><![CDATA[
<p>This is how it would look with explicit labels and comefrom:<p><pre><code>    puts("foo");
    before_defer0:
    comefrom after_defer1;
    puts("bar");
    after_defer0:
    comefrom before_defer0;
    puts("baz");
    before_defer1:
    comefrom before_ret;
    puts("qux");
    after_defer1:
    comefrom before_defer1;
    puts("corge");
    before_ret:
    comefrom after_defer0;
    return;
</code></pre>
---<p>`defer` is obviously not implemented in this way, it will re-order the code to flow top-to-bottom and have fewer branches, but the control flow is effectively the same thing.<p>In theory a compiler could implement `comefrom` by re-ordering the basic blocks like `defer` does, so that the actual runtime evaluation of code is still top-to-bottom.</p>
]]></description><pubDate>Fri, 20 Feb 2026 15:32:24 +0000</pubDate><link>https://news.ycombinator.com/item?id=47089268</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47089268</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47089268</guid></item><item><title><![CDATA[New comment by sparkie in "Defer available in gcc and clang"]]></title><description><![CDATA[
<p>Defer might be better than nothing, but it's still a poor solution. An obvious example of a better, structural solution is C#'s `using` blocks.<p><pre><code>    using (var resource = acquire()) {

    } // implicit resource.Dispose();
</code></pre>
While we don't have the same simplicity in C because we don't use this "disposable" pattern, we could still perhaps learn something from syntax and use a secondary block to have scoped defers. Something like:<p><pre><code>    using (auto resource = acquire(); free(resource)) {

    } // free(resource) call inserted here.
</code></pre>
That's no so different to how a `for` block works:<p><pre><code>    for (auto it = 0; it < count; it++) {

    } // automatically inserts it++; it < count; and conditional branch after secondary block of for loop.
</code></pre>
A trivial "hack" for this kind of scoped defer would be to just wrap a for loop in a macro:<p><pre><code>    #define using(var, acquire, release) \
        auto var = (acquire); \
        for (bool var##_once = true; var##_once; var##_once = false, (release))

    using (foo, malloc(szfoo), free(foo)) {
        using (bar, malloc(szbar), free(bar)) {
            ...
        } // free(bar) gets called here.
    } // free(foo) gets called here.</code></pre></p>
]]></description><pubDate>Fri, 20 Feb 2026 14:58:26 +0000</pubDate><link>https://news.ycombinator.com/item?id=47088814</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47088814</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47088814</guid></item><item><title><![CDATA[New comment by sparkie in "Defer available in gcc and clang"]]></title><description><![CDATA[
<p>Defer is a restricted form of COMEFROM with automatic labels. You COMEFROM the end of the next `defer` block in the same scope, or from the end of the function (before `return`) if there is no more `defer`. The order of execution of defer-blocks is backwards (bottom-to-top) rather than the typical top-to-bottom.<p><pre><code>    puts("foo");
    defer { puts("bar"); }
    puts("baz");
    defer { puts("qux"); }
    puts("corge");
    return;
</code></pre>
Will evaluate:<p><pre><code>    puts("foo");
    puts("baz");
    puts("corge");
    puts("qux");
    puts("bar");
    return;</code></pre></p>
]]></description><pubDate>Fri, 20 Feb 2026 14:32:09 +0000</pubDate><link>https://news.ycombinator.com/item?id=47088500</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=47088500</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47088500</guid></item><item><title><![CDATA[New comment by sparkie in "Thoughts on Generating C"]]></title><description><![CDATA[
<p>Compile using `-fkeep-inline-functions`.</p>
]]></description><pubDate>Tue, 10 Feb 2026 02:27:33 +0000</pubDate><link>https://news.ycombinator.com/item?id=46954573</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=46954573</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46954573</guid></item><item><title><![CDATA[New comment by sparkie in "Thoughts on Generating C"]]></title><description><![CDATA[
<p>`inline` is a hint, but he declares `static_inline` in the preprocessor to include `__attribute__((__always_inline__))`, which is more than just a hint. However, even `always_inline` may be troublesome over translation units, though we can still inline things in different translation units if using `-flto`, I believe there are occasional bugs. For libraries we'd also want to use `-ffat-lto-objects`.</p>
]]></description><pubDate>Tue, 10 Feb 2026 02:26:13 +0000</pubDate><link>https://news.ycombinator.com/item?id=46954558</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=46954558</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46954558</guid></item><item><title><![CDATA[New comment by sparkie in "Thoughts on Generating C"]]></title><description><![CDATA[
<p>A subset of C could still use existing C compilers and get the optimizations. The front-end would just restrict what can be expressed in it.</p>
]]></description><pubDate>Tue, 10 Feb 2026 02:21:21 +0000</pubDate><link>https://news.ycombinator.com/item?id=46954529</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=46954529</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46954529</guid></item><item><title><![CDATA[New comment by sparkie in "Thoughts on Generating C"]]></title><description><![CDATA[
<p>`uintptr_t` and `intptr_t` are integer types large enough to hold a pointer. They're not pointer types (They're also optional in the standard).<p>In the first `my_func`, there is the possiblity that `a` and `b` are equal if their struct layouts are equivalent (or one has a proper subset of the other's fields in the same order). To tell the compiler they don't overlap we would use `(strong_type1 *restrict a, strong_type2 *restrict b)`.<p>There's also the possibility that the pointers could point to the same address but be non-equal - eg if LAM/UAI/TBI are enabled, a simple pointer equality comparison is not sufficient because the high bits may not be equal. Or on platforms where memory access is always aligned, the low bits may be not equal. These bits are sometimes used to <i>tag</i> pointers with additional information.</p>
]]></description><pubDate>Tue, 10 Feb 2026 02:10:27 +0000</pubDate><link>https://news.ycombinator.com/item?id=46954464</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=46954464</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46954464</guid></item><item><title><![CDATA[New comment by sparkie in "Building Your Own Efficient uint128 in C++"]]></title><description><![CDATA[
<p>> It probably is<p>This was my point. It may be `unsigned long` on his machine (or any that use LP64), but that isn't what `uint64_t` means. `uint64_t` means a type that is 64-bits, whereas `unsigned long` is simply a type that is larger than `unsigned int` and at least 32-bits, and `unsigned long long` is a type that is at least as large as `unsigned long` and is at least 64-bits.<p>I was not aware of compilers rejecting the equivalence of `long` and `long long` on LP64. GCC on Linux certainly doesn't. On windows it would be the case because it uses LLP64 where `long` is 32-bits and `long long` is 64-bits.<p>An intrinsic like `_addcarry_u64` <i>should</i> be using the `uint64_t` type, since its behavior depends on it being precisely 64-bits, which neither `long` nor `long long` guarantee. Intel's intrinsics spec defines it as using the type `unsigned __int64`, but since `__int64` is not a standard type, it has probably implemented as a typedef or `#define __int64 long long` by the compiler or `<immintrin.h>` he is using.</p>
]]></description><pubDate>Mon, 02 Feb 2026 11:24:26 +0000</pubDate><link>https://news.ycombinator.com/item?id=46854754</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=46854754</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46854754</guid></item><item><title><![CDATA[New comment by sparkie in "Actors: A Model of Concurrent Computation [pdf] (1985)"]]></title><description><![CDATA[
<p>I was disappointed when MS discontinued Axum, which I found pleasant to use and thought the language based approach was nicer than a library based solution like Orleans.<p>The Axum language had `domain` types, which could contain one or more `agent` and some state. Agents could have multiple functions and could share domain state, but not access state in other domains directly. The programming model was passing messages between agents over a typed `channel` using directional infix operators, which could also be used to build process pipelines. The channels could contain `schema` types and a state-machine like protocol spec for message ordering.<p>It didn't have "classes", but Axum files could live in the same projects as regular C# files and call into them. The C# compiler that came with it was modified to introduce an `isolated` keyword for classes, which prevented them from accessing `static` fields, which was key to ensuring state didn't escape the domain.<p>The software and most of the information was scrubbed from MS own website, but you can find an archived copy of the manual[1]. I still have a copy of the software installer somewhere but I doubt it would work on any recent Windows.<p>Sadly this project was axed before MS had embraced open source. It would've been nice if they had released the source when the decided to discontinue working on it.<p>[1]:<a href="https://web.archive.org/web/20110629202213/http://download.microsoft.com/download/B/D/5/BD51FFB2-C777-43B0-AC24-BDE3C88E231F/Axum%20Programmers%20Guide.pdf" rel="nofollow">https://web.archive.org/web/20110629202213/http://download.m...</a></p>
]]></description><pubDate>Mon, 02 Feb 2026 07:09:42 +0000</pubDate><link>https://news.ycombinator.com/item?id=46853276</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=46853276</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46853276</guid></item><item><title><![CDATA[New comment by sparkie in "Building Your Own Efficient uint128 in C++"]]></title><description><![CDATA[
<p>SIMD is for performing parallel operations on many smaller types. It can help with some cryptography, but It doesn't necessarily help when performing single arithmetic operations on larger types. Though it does help when performing logic and shift operations on larger types.<p>If we were performing 128-bit arithmetic in parallel over many values, then a SIMD implementation may help, but without a SIMD equivalent of `addcarry`, there's a limit to how much it can help.<p>Something like this could potentially be added to AVX-512 for example by utilizing the `k` mask registers for the carries.<p>The best we have currently is `adcx` and `adox` which let us use two interleaved addcarry chains, where one utilizes the carry flag and the other utilizes the overflow flag, which improves ILP. These instructions are quite niche but are used in bigint libraries to improve performance.</p>
]]></description><pubDate>Mon, 02 Feb 2026 05:10:00 +0000</pubDate><link>https://news.ycombinator.com/item?id=46852651</link><dc:creator>sparkie</dc:creator><comments>https://news.ycombinator.com/item?id=46852651</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=46852651</guid></item></channel></rss>