<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: malcolmstill</title><link>https://news.ycombinator.com/user?id=malcolmstill</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Fri, 05 Jun 2026 02:48:15 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=malcolmstill" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by malcolmstill in "System design and the cost of architectural complexity (2013)"]]></title><description><![CDATA[
<p>Can you define your use of DP here? I'm not sure if you mean dynamic programming, or design pattern or something else, and am curious about your insight.</p>
]]></description><pubDate>Fri, 07 Apr 2023 15:02:36 +0000</pubDate><link>https://news.ycombinator.com/item?id=35482274</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=35482274</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35482274</guid></item><item><title><![CDATA[New comment by malcolmstill in "Zig as an alternative to writing unsafe Rust"]]></title><description><![CDATA[
<p>I see you what you mean. Yeah, I suppose if you are writing a library you might want to be more deliberate in the error set. Maybe explicitly writing out the error set is what you want in that situation. Rewriting the example:<p><pre><code>    fn someFunction(a: usize) MyError!usize {
        if (a < 10) return error.LessThanTen;
    
        const b = try anotherFunction(a);
    
        return 2 * b;
    }
    
    fn anotherFunction(x: usize) MyError!usize {
        if (x < 20) return error.LessThanTwenty;
    
        return x * 3;
    }

    const MyError = error {
        LessThanTen,
        LessThanTwenty
    }
</code></pre>
> That feels very limiting, I often use error types to e.g., attach data about the error. Is there a more general mechanism for sum types for when this shorthand doesn't apply?<p>I agree it's limiting. It obviously is going to depend on your application, but I have largely done without annotating errors with extra information (that maybe speaks more to the seriousness of my zig projects than to that approach to error handling as being sufficient!).<p>One pattern I have used (in e.g. a parser) is additionally passing in a pointer to a sum type:<p><pre><code>    fn parse(allocator: *mem.Allocator, tokens: Tokens, parse_error: *ParseError) !AST
</code></pre>
The `parse_error` can be set if an error condition occurs. I concede that that's a little clumsy</p>
]]></description><pubDate>Tue, 07 Mar 2023 23:50:38 +0000</pubDate><link>https://news.ycombinator.com/item?id=35063140</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=35063140</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35063140</guid></item><item><title><![CDATA[New comment by malcolmstill in "Zig as an alternative to writing unsafe Rust"]]></title><description><![CDATA[
<p>I did use the example of long run of module names, and I do take your point about `use` (though I have to sometimes read the very top of a file too!)...but the same applies to a lesser extent to the "last mile" module (e.g. `String::from`, `Vec::new`) which will be seen throughout any rust code.<p>> If rust used a `.` as a separator, it's unclear if you're descending into modules or calling a function chain<p>Interestingly, from the zig documentation:<p><pre><code>    Zig source files are implicitly structs, with a name equal to the file's basename with the extension truncated. @import returns the struct type corresponding to the file.
</code></pre>
This means that there isn't really any difference between accessing a struct field and accessing something in module...the module is also a kind of struct (and rust, as in zig, differentiating struct field access vs function invocation is possible because of the parens in the latter).</p>
]]></description><pubDate>Tue, 07 Mar 2023 23:03:07 +0000</pubDate><link>https://news.ycombinator.com/item?id=35062586</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=35062586</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35062586</guid></item><item><title><![CDATA[New comment by malcolmstill in "Zig as an alternative to writing unsafe Rust"]]></title><description><![CDATA[
<p>> Doesn't that risk introducing accidental breaking changes by adding a new error to the set in the implementation, since the set of errors is inferred from the implementation?<p>Do you have an illustrative example? (I'm not implying it's not possible, just trying to think of a good example so I can give a good answer)<p>> since callers have to exhaustively match on the error conditions<p>If it's exhaustiveness that you're referring to, zig will make you handle all the possible errors (you can still do a catch all type thing when handling errors, which has the potential to "hide" an error that you otherwise wanted to handle explicitly).<p>> Can you have data in the variants of the error enumeration<p>No, they compile to just integers. Essentially it compiles to the same as C function that returns an `int` representing the error (with your actual return type passed in as a pointer, say).<p>Another limitation of zig error values is I think they're globally scoped, so you potentially could have two libraries have clashing error names that you then can't differentiate (I don't know if there are any plans to try and resolve that).<p>I will say that this automatic error set inference gives writing zig code this lovely "flow", where I do some error checks at the top of the function and early return some errors (which I just invent the names of there and then) and then move onto the happy path of the function, happy in the knowledge that the error handling is already "correct" (in that if the error isn't handled it'll (typically) bubble all the way up to main and exit the program). Any refinement on how a specific error is handled, I can go back to an appropriate place in the call stack and handle it. I always feel like it's helping me write correct code.</p>
]]></description><pubDate>Tue, 07 Mar 2023 22:34:56 +0000</pubDate><link>https://news.ycombinator.com/item?id=35062260</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=35062260</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35062260</guid></item><item><title><![CDATA[New comment by malcolmstill in "Zig as an alternative to writing unsafe Rust"]]></title><description><![CDATA[
<p>So usually you don't have to specify the error type. The Zig compiler works out what errors are returned from the function by looking at any errors returned directly or errors returned from other functions called within the body of the function. That set of errors forms an enum that is the actual error type, you just don't have to write that out explicitly. An example might be:<p><pre><code>    fn someFunction(a: usize) !usize {
        if (a < 10) return error.LessThanTen;
    
        const b = try anotherFunction(a);
    
        return 2 * b;
    }
    
    fn anotherFunction(x: usize) !usize {
        if (x < 20) return error.LessThanTwenty;
    
        return x * 3;
    }
</code></pre>
The compiler infers the error type of `someFunction` as:<p><pre><code>    error {
        LessThanTen,
        LessThanTwenty
    }
</code></pre>
When you then `switch` on an error type, the compiler will exhaustively check that you have handled all the cases.<p>Note the "(mostly) equivalently" was a reference to the fact that Zig errors can't (currently) contain any other information, whereas an error in rust can carry other information.<p>Also note that the compiler can't infer the error type in all case, for example in the case of a recursive function. In that case you do need to explicitly write out the error set.</p>
]]></description><pubDate>Tue, 07 Mar 2023 22:00:38 +0000</pubDate><link>https://news.ycombinator.com/item?id=35061891</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=35061891</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35061891</guid></item><item><title><![CDATA[New comment by malcolmstill in "Zig as an alternative to writing unsafe Rust"]]></title><description><![CDATA[
<p>To be honest that's the major one for me. Someone else has mentioned lifetime annotations, but those uncommon enough that I don't find it much of an issue.<p>If I was to think about it: comparing rust to zig, zig benefits a lot from error and optional types having their own syntax rather than being treated like any other type. For example a return type of:<p><pre><code>    Result<Option<usize>, Error>>
</code></pre>
in rust is rendered (mostly) equivalently in zig as<p><pre><code>    !?usize
</code></pre>
Note: there are some options in rust for cleaning up errors such as the anyhow library.<p>Disclaimer: I'm a zig fan and contribute monetarily so please weight anything I say on zig vs rust with that in mind. (I do write rust at work though)</p>
]]></description><pubDate>Tue, 07 Mar 2023 21:08:07 +0000</pubDate><link>https://news.ycombinator.com/item?id=35061236</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=35061236</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35061236</guid></item><item><title><![CDATA[New comment by malcolmstill in "Zig as an alternative to writing unsafe Rust"]]></title><description><![CDATA[
<p>There are a number of sources of noise in rust, but the one I find most annoying (because it's also so common) is the double colon. My current theory is that it's because the colon is the same height as lowercase letters.<p>If you end up with a long::run::of::module::names, I find it all just blurs into one.</p>
]]></description><pubDate>Tue, 07 Mar 2023 19:58:57 +0000</pubDate><link>https://news.ycombinator.com/item?id=35060360</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=35060360</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35060360</guid></item><item><title><![CDATA[New comment by malcolmstill in "Conventional wisdom as an anti-pattern"]]></title><description><![CDATA[
<p>> If a test never fails, is it a good test? If I have to change a test everytime I change the implementation, is it a good test? Writing good tests is really difficult.<p>If you don't like writing / maintaining tests or don't have the time, let the computer write them for you! [0][1]<p>[0] <a href="https://insta.rs/" rel="nofollow">https://insta.rs/</a>
[1] <a href="https://vitest.dev/guide/snapshot.html" rel="nofollow">https://vitest.dev/guide/snapshot.html</a></p>
]]></description><pubDate>Mon, 27 Feb 2023 20:17:06 +0000</pubDate><link>https://news.ycombinator.com/item?id=34961336</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=34961336</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=34961336</guid></item><item><title><![CDATA[New comment by malcolmstill in "Zig's multi-sequence for loops"]]></title><description><![CDATA[
<p>To expand on the parent and grandparent:<p>Laremere is correct in that there is no "magic" built-in understanding of iterators in the language, i.e. under the hood calling a `.next()` method, without explicitly having to call it. That _would_ violate the no hidden flow control maxim.<p>However, as Jayschwa points out, Zig's `while` loop will bind the result of its expression (in its own block scope) if it is non-null and otherwise exit the loop. This gives you essentially the same as a for loop that has some language-level knowledge of the iterator pattern, except there is no hidden flow control (I have to explicitly call `next`).<p>And indeed the Zig standard library is replete with iterators (and in most of the Zig code I write I will will write iterators for my own collections). For example, `mem.split` returns an iterator:<p><pre><code>    var it = mem.split(...);
    
    // it.next() returns null after we run out of
    // split text and the while loop exits
    while (it.next()) |substr| {
         // In here we have a non-nil substr
    }  
</code></pre>
> Plus I imagine it's a lot easier for the compiler to perform optimizations this way.<p>That's an interesting point: does Zig miss out on some optimisation possibilities with iterators given they are not a language-level construct? I don't know.</p>
]]></description><pubDate>Mon, 27 Feb 2023 18:48:31 +0000</pubDate><link>https://news.ycombinator.com/item?id=34960332</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=34960332</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=34960332</guid></item><item><title><![CDATA[New comment by malcolmstill in "Why would anyone need JavaScript generator functions?"]]></title><description><![CDATA[
<p>I could write this against a few other replies but I will write it here. Moreover, I don't think  I'm going to say anything that hasn't already been covered by other people, but I am going to attempt to distil down the arguments.<p>- The benefits of generators are, in a large part, the benefits of using iterators<p>- What are the benefits of using iterators? As you say, one benefit is that calling `next` on an iterator performs a single unit of work getting the next value. This let's you avoid e.g. allocating intermediate arrays, let's you do infinite streams, etc. Compare that to calling `map` on a list...you have to consume the entire list.<p>- A second benefit of iterators is that of scope. When I call `next` on an iterator I get the next value in the scope of the caller. This is particularly useful in a language with function colouring, because use of the `next` value can match what is required of the caller. E.g. the caller may want to await a function using some field of the `next` value and this is totally fine. Compare that to calling `map` with a lambda and wanting to `await` inside the lambda...the problem is you are now in the wrong scope and can't `await`.<p>- So where do generators come in? Well they are just syntactic sugar that will generate the state machine that you would otherwise have to implement by hand in your iterator. In that sense you don't need generators at all...<p>- BUT, with generators you can do things that would technically be possible with iterators but would be so clumsy to implement (I'm thinking here of coroutine libraries) that having them as a distinct feature makes sense.</p>
]]></description><pubDate>Mon, 07 Nov 2022 20:38:03 +0000</pubDate><link>https://news.ycombinator.com/item?id=33512057</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=33512057</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=33512057</guid></item><item><title><![CDATA[New comment by malcolmstill in "Ask HN: When do you think Wayland will be broadly supported?"]]></title><description><![CDATA[
<p>The Wayland protocol is fine and provides the modern features expected (“every frame is perfect”).<p>But X is two things: a protocol and a de facto standard server that window managers could easily interface with.<p>I wonder if we’d be in a different place if Wayland as well as offering the protocol also offered a de facto standard server (not simply a reference implementation in weston) with a window manager protocol that more or less forwards on client <-> server messages that a window manager would care about. Client buffers shared with the server can also be shared with the (separate) window manager process which then shares its composited buffer with the server for final rendering.</p>
]]></description><pubDate>Sat, 30 Jul 2022 13:23:44 +0000</pubDate><link>https://news.ycombinator.com/item?id=32286601</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=32286601</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=32286601</guid></item><item><title><![CDATA[New comment by malcolmstill in "Rich Harris joins Vercel to work on Svelte full time"]]></title><description><![CDATA[
<p>> Things that are easy in React at runtime turn out to be surprisingly difficult in Svelte<p>Do you have some specific examples?</p>
]]></description><pubDate>Fri, 12 Nov 2021 01:48:22 +0000</pubDate><link>https://news.ycombinator.com/item?id=29195480</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=29195480</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=29195480</guid></item><item><title><![CDATA[New comment by malcolmstill in "Scottish Café"]]></title><description><![CDATA[
<p>It could be related to historic Scotland -> Poland immigration:<p><a href="https://en.wikipedia.org/wiki/Scottish_diaspora#Poland" rel="nofollow">https://en.wikipedia.org/wiki/Scottish_diaspora#Poland</a></p>
]]></description><pubDate>Sun, 30 May 2021 12:17:50 +0000</pubDate><link>https://news.ycombinator.com/item?id=27332701</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=27332701</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=27332701</guid></item><item><title><![CDATA[New comment by malcolmstill in "Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)"]]></title><description><![CDATA[
<p>Of all the absolutely fantastic stuff that Zig gets right, I think my favourite is the error handling.<p>While it would be cool to get an error payload, I would hope that if that was added to the language, that it doesn't affect the current ergonomics of error handling.<p>Where I've really needed to get some data back out, I've passed in a pointer to a struct that gets populated.</p>
]]></description><pubDate>Fri, 19 Feb 2021 19:36:04 +0000</pubDate><link>https://news.ycombinator.com/item?id=26197079</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=26197079</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=26197079</guid></item><item><title><![CDATA[New comment by malcolmstill in "U.S. has its wettest 12 months on record again"]]></title><description><![CDATA[
<p>Assuming independent events (a bad assumption no doubt) then you're looking for 1 - the probability that for 20 years straight you don't have the event happening.<p>- E event happens in given year
- N event doesn't happen in given year<p>Then P(E) = 1/125. Conversely P(N) = 1-1/125.<p>We're looking for 1-P(NNNNNNNNNNNNNNNNNNNN) = 1 - (1-1/125)^20 = 15%<p>Though I'm sure someone will tell me how I'm wrong</p>
]]></description><pubDate>Tue, 09 Jul 2019 23:22:01 +0000</pubDate><link>https://news.ycombinator.com/item?id=20397782</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=20397782</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=20397782</guid></item><item><title><![CDATA[New comment by malcolmstill in "Ask HN: Who is hiring? (July 2018)"]]></title><description><![CDATA[
<p>To clarify, the position is in Newcastle, Edinburgh or Remote within the UK.</p>
]]></description><pubDate>Wed, 04 Jul 2018 14:43:19 +0000</pubDate><link>https://news.ycombinator.com/item?id=17457514</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=17457514</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17457514</guid></item><item><title><![CDATA[New comment by malcolmstill in "Ask HN: Who is hiring? (July 2018)"]]></title><description><![CDATA[
<p>SoPost | Edinburgh, London, Newcastle, UK | REMOTE<p>SoPost is on a mission to build the world's best product sampling platform, and we are hiring into our platform team. We are currently seeking engineers (design, operations and programmers) to expand the team to help with the growth of our business.<p>We use Elixir / Elm / Python / Rust / Postgres / GraphQL / Kubernetes, but you don't necessarily need to be familiar with any of these...we'd like to speak to you if you're interested generally in functional programming.<p>Check out <a href="https://jobs.sopost.com/" rel="nofollow">https://jobs.sopost.com/</a> or email me directly at mstill@sopost.com.</p>
]]></description><pubDate>Mon, 02 Jul 2018 21:04:38 +0000</pubDate><link>https://news.ycombinator.com/item?id=17445322</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=17445322</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17445322</guid></item><item><title><![CDATA[New comment by malcolmstill in "The Bipolar Lisp Programmer (2007)"]]></title><description><![CDATA[
<p>I'm writing a Wayland compositor in Common Lisp: <a href="https://github.com/malcolmstill/ulubis" rel="nofollow">https://github.com/malcolmstill/ulubis</a></p>
]]></description><pubDate>Tue, 24 Jan 2017 15:34:33 +0000</pubDate><link>https://news.ycombinator.com/item?id=13472118</link><dc:creator>malcolmstill</dc:creator><comments>https://news.ycombinator.com/item?id=13472118</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=13472118</guid></item></channel></rss>