<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: Twey</title><link>https://news.ycombinator.com/user?id=Twey</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Mon, 13 Apr 2026 19:02:52 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=Twey" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by Twey in "All elementary functions from a single binary operator"]]></title><description><![CDATA[
<p>Depending on your lambda calculus! From a categorical perspective a lambda calculus is just a nice syntax for Cartesian closed categories (or similar, e.g. *-autonomous categories for linear lambda calculus) so you can use it to reason about anything you can fit into that mould. For example, Paul Taylor likes to do exactly this: <a href="https://www.paultaylor.eu/ASD/analysis#lamcra" rel="nofollow">https://www.paultaylor.eu/ASD/analysis#lamcra</a></p>
]]></description><pubDate>Mon, 13 Apr 2026 13:12:14 +0000</pubDate><link>https://news.ycombinator.com/item?id=47751465</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47751465</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47751465</guid></item><item><title><![CDATA[New comment by Twey in "Why are we still using Markdown?"]]></title><description><![CDATA[
<p>If we're going to define a programming language as one that is Turing complete, it's important (in a kind of pedantic sense) to note that that includes HTML (with CSS), which can be used to encode a Rule 110 automaton, and excludes C, whose standard imposes an (implementation-defined) upper bound on accessible memory, meaning it can never, even in principle†, similarly a Turing machine, which has infinite storage. This is probably not what was intended :)<p>† Obviously, for physical reasons given our current understanding of cosmology, no _implementation_ of a language can ever really be Turing-complete, but some language definitions are theoretically compatible with Turing-completeness, and others aren't.</p>
]]></description><pubDate>Sat, 04 Apr 2026 13:20:55 +0000</pubDate><link>https://news.ycombinator.com/item?id=47638834</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47638834</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47638834</guid></item><item><title><![CDATA[New comment by Twey in "C++26 is done: ISO C++ standards meeting Trip Report"]]></title><description><![CDATA[
<p>I think it's also true that, regardless of the desirability of the feature at the time (which sibling comments discuss eloquently) people who've bought into a language are usually quite wary of also buying into extensions to that language. The very act of ratification by the committee gives this proposal a ‘feature’ that the DMC++ extension lacked in compatibility expectations over time and across implementations — it's not necessarily a comment on the technical quality or desirability of the work itself.</p>
]]></description><pubDate>Mon, 30 Mar 2026 17:25:45 +0000</pubDate><link>https://news.ycombinator.com/item?id=47577172</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47577172</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47577172</guid></item><item><title><![CDATA[New comment by Twey in "C++26 is done: ISO C++ standards meeting Trip Report"]]></title><description><![CDATA[
<p>> It is the right tradeoff to write those structs for libraries that absolutely have to avoid dynamic dispatch. In other cases it is better to give a trait object.<p>IMO it is a hack to use dynamic dispatch (a runtime behaviour with honestly quite limited use cases, like plugin functionality) to get existential types (a type system feature). If you are okay with parametric polymorphism/generics (universal types) you should also be okay with RPIT (existential types), which is the same semantic feature with a different syntax, e.g. you can get the same effect by CPS-encoding except that the syntax makes it untenable.<p>Because dynamic dispatch is a runtime behaviour it inherits a bunch of limitations that aren't inherent to existential types, a.k.a. Rust's ‘`dyn` safety’ requirements. For example, you can't have (abstract) associated types or functions associated with the type that don't take a magic ‘receiver’ pointer that can be used to look up the vtable.</p>
]]></description><pubDate>Mon, 30 Mar 2026 17:18:58 +0000</pubDate><link>https://news.ycombinator.com/item?id=47577087</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47577087</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47577087</guid></item><item><title><![CDATA[New comment by Twey in "Tired of AI When will this era end?"]]></title><description><![CDATA[
<p>Vibe coding is painful mostly just because natural language is bad for programming in. Give it a couple of iterations and statistical programming will be at least as enjoyable as deterministic programming is today :)</p>
]]></description><pubDate>Wed, 25 Mar 2026 23:46:30 +0000</pubDate><link>https://news.ycombinator.com/item?id=47524882</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47524882</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47524882</guid></item><item><title><![CDATA[New comment by Twey in "Why I Vibe in Go, Not Rust or Python"]]></title><description><![CDATA[
<p>Right… but what I'm saying is that for the most part if the compiler pushes back on your LLM-generated code it's because that code is wrong. In the LLM world these are known as ‘guardrails’ and they're great because they a) provide some level of automated verification of the generated code and b) provide actionable feedback to the model to fix the code, where otherwise a human would have to notice the bug and enter the loop. The compiler pushing back on things early is a big positive for vibe coding.<p>In this particular case maybe Rust isn't the right choice because (idiomatic) Rust is designed for the case where you care about your memory management, and for your blog you probably don't. But that's a comment on the suitability of Rust for blogs, not a comment on the suitability of Rust for vibe coding.</p>
]]></description><pubDate>Mon, 23 Mar 2026 17:17:46 +0000</pubDate><link>https://news.ycombinator.com/item?id=47492360</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47492360</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47492360</guid></item><item><title><![CDATA[New comment by Twey in "Why I Vibe in Go, Not Rust or Python"]]></title><description><![CDATA[
<p>The case given here for ‘why Go, not Python’ is just as applicable for ‘why Rust, not Go’.<p>> The borrow checker catches real bugs. The type system is rigorous. The compiler says no, and when it says no, it’s right. The problem is that the compiler says no too much.<p>> When an AI writes Rust, the borrow checker fights the generated code. I — the human — spend my taste budget on lifetime annotations instead of architecture. Instead of saying “why do we keep both around?” — five words that collapse complexity — I’m saying “add a .clone() here” or “wrap this in Arc<Mutex<>>.” I’m using Layer 5, the most expensive layer, on problems the language invented.<p>These paragraphs are inconsistent. Either lifetimes catch real bugs — i.e. they reflect the ‘real’ (runtime) world, and when the compiler rejects some generated code it's because that code is buggy — or the language merely invented the problems they exist to solve and you're wasting your time thinking about them. (In my experience it's about 80:20 respectively, but for the level of code LLMs generate probably higher.)<p>> Go has goroutines. You write `go func()` and it works. Rust has colored functions.<p>Go also has coloured functions, but the only functions that are allowed to not be async are FFI. Go marks all functions as async just as JavaScript marks all return types as `any` — with the exception that sometimes Go is wrong and you have to remember where.<p>> One crate uses async-std. Now you have two runtimes.<p>Only if you start an async-std runtime. (There are compatibility options, too.) There are certainly occasional pitfalls when writing cross-runtime code in Rust, but relatively few these days, and not really the ones the article worries about.<p>> Come back to a Rust project after three months. Run `cargo update`. Half your transitive dependencies don’t compile because a trait bound changed in a crate you’ve never heard of.<p>If you lock your dependencies (which is in fact the case by default, and what you're explicitly opting out of by running `cargo update`) this doesn't happen. If you change the version of a Go dependency, it may also change API. Rust just has a tool to automate this workflow. If you choose not to use it you'll get the Go experience.<p>There are valid reasons (IMHO) to reject Rust for vibe coding (all else being equal). They're not these though.</p>
]]></description><pubDate>Mon, 23 Mar 2026 01:44:26 +0000</pubDate><link>https://news.ycombinator.com/item?id=47484524</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47484524</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47484524</guid></item><item><title><![CDATA[New comment by Twey in "The Isolation Trap: Erlang"]]></title><description><![CDATA[
<p>No, a <i>message</i> is always consistent, both in the actor model and in hardware memory.  My point is just that if you restrict your messages to those supported by hardware memory, you get exactly the same semantics when sharing the actor as you do for hardware shared memory.  However, the actor model _also_ allows you to define higher-level messages that are consistent in a way that is defined by the application semantics.<p>>> you can emulate a Turing-complete computer in a Turing-complete language<p>> If you've created semantics that allow for incomplete reads/writes, you allow incomplete reads/writes.<p>That's true, but isn't entirely relevant to the discussion for a few reasons. First, Turing-completeness does not require the existence of race conditions; it is perfectly possible to have a Turing-complete language (for example, standard Turing machines!) that doesn't have the ability to define data races. Second, my entire point here is that you don't have to ‘create semantics that allow for incomplete reads/writes’. That semantics is a subset of the standard actor semantics.  In fact, I am claiming more broadly that <i>all</i> reads/writes are either complete or incomplete (to borrow your terminology) <i>depending on your semantic perspective</i>. The reads/writes of standard hardware shared memory are also ‘complete’ from the perspective of reading/writing individual words; the problem is just that almost all applications need a notion of ‘completeness’ that is higher-level than that, which gives rise to the (relativistic!) notion of ‘data race’.</p>
]]></description><pubDate>Thu, 19 Mar 2026 14:26:40 +0000</pubDate><link>https://news.ycombinator.com/item?id=47440112</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47440112</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47440112</guid></item><item><title><![CDATA[New comment by Twey in "The Isolation Trap: Erlang"]]></title><description><![CDATA[
<p>The shared memory in the <i>Mem</i> setup is not the local copies of the values after reading from <i>Mem</i> (just as the registers or private memory ranges of a thread are not shared) but (the internal state of) the <i>Mem</i> actor itself.<p>To phrase my point here a bit differently, the distinction between a data race and a logical race is purely the scope of the expected consistency. In the standard multi-threaded case as well, if you read a single word from the memory it will definitely be consistent — you'll get the result of either one write or another, never half of the word from one write and half from the other. But values in real programs are usually bigger than a single word, and once you read <i>two</i> words from the memory it becomes possible (ignoring for the sake of argument the facilities modern memory provides for reading larger memory ranges atomically; feel free to replace ‘word’ with your atomic unit of choice) to get one word from one write and one word from another. As words these are consistent — they're both valid words and they both come from an intentional write — but put together they may not form a coherent value of the higher-level type you meant to read. This is how you get ‘corrupted’ data: the notion of corruption comes not from the memory semantics but from the semantics of the type that the memory is being used to represent. This applies exactly the same to <i>Mem</i>: each word is, as you say, consistent, but if you try to read a value by doing two reads, the resulting value may be ‘corrupt’ (formed by the interleaving of two writes) depending on what other threads are doing with <i>Mem</i> at the time.</p>
]]></description><pubDate>Tue, 17 Mar 2026 15:21:46 +0000</pubDate><link>https://news.ycombinator.com/item?id=47413957</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47413957</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47413957</guid></item><item><title><![CDATA[New comment by Twey in "The Isolation Trap: Erlang"]]></title><description><![CDATA[
<p>But there are data races.<p><i>Mem</i> as I set it out above is an example of multi-threaded, mutable data. Another process can't alter the data you've received, indeed, just as in a shared-memory system another thread can't alter the data after you copy it out of shared memory into your registers or an unshared memory space. But if you're storing the data in shared memory (a.k.a. requesting it from <i>Mem</i> every time) then you are racing with other actors who have access to <i>Mem</i>.</p>
]]></description><pubDate>Mon, 16 Mar 2026 13:31:00 +0000</pubDate><link>https://news.ycombinator.com/item?id=47398780</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47398780</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47398780</guid></item><item><title><![CDATA[New comment by Twey in "The Isolation Trap: Erlang"]]></title><description><![CDATA[
<p>The <i>operations</i> are atomic because of the single-threaded nature of actors. But the operations can be arbitrarily ordered, except for the pairwise ordering constraint (which mirrors the happens-before relation on memory within a thread). If your memory actor has operations like ‘read address’ and ‘write address’ then yes, you precisely get the behaviour we enjoy from shared memory: if you read one address A then address B someone might have changed both of them in the meantime, and if you write A then read it back it might have been changed in the meantime.<p>The difference is that you're not limited to just ‘read address’ and ‘write address’ operations: the shared actor gets to define higher-level operations that are atomic over larger sections of code.</p>
]]></description><pubDate>Sun, 15 Mar 2026 06:14:40 +0000</pubDate><link>https://news.ycombinator.com/item?id=47384780</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47384780</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47384780</guid></item><item><title><![CDATA[New comment by Twey in "I beg you to follow Crocker's Rules, even if you will be rude to me"]]></title><description><![CDATA[
<p>Adapting your communication doesn't have to imply deception or even insincerity, it just means understanding what's important to your target audience and making sure to address it. Sometimes that's something like financial impact or user focus; sometimes it's emotional reassurance or intellectual challenge.</p>
]]></description><pubDate>Sun, 15 Mar 2026 06:14:00 +0000</pubDate><link>https://news.ycombinator.com/item?id=47384775</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47384775</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47384775</guid></item><item><title><![CDATA[New comment by Twey in "I beg you to follow Crocker's Rules, even if you will be rude to me"]]></title><description><![CDATA[
<p>Sure, if we want to shift topic from directness to density, but that's not a cultural difference either: all (spoken) languages famously transmit at about 39 bits per second [1]. Specific idioms, especially newer ones, might be a bit more or less information-dense, but there will always be others that make up for it. And if an idiom falls too far below the 39 B/s rate it'll get worn down over time to something shorter.<p>If you are shortening your communication you are doing it by reducing the information content. In some cultures it's acceptable to spend longer buying bread than in others, so you might take the time to exchange more information with the baker. But that is a (to them, if not to you) valuable interaction that they have chosen to have, filled with information whose exchange is (to them) just as important as the price of bread.<p>[1]: <a href="https://www.science.org/doi/10.1126/sciadv.aaw2594" rel="nofollow">https://www.science.org/doi/10.1126/sciadv.aaw2594</a></p>
]]></description><pubDate>Sat, 14 Mar 2026 18:10:46 +0000</pubDate><link>https://news.ycombinator.com/item?id=47379402</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47379402</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47379402</guid></item><item><title><![CDATA[New comment by Twey in "I beg you to follow Crocker's Rules, even if you will be rude to me"]]></title><description><![CDATA[
<p>The Gladwellian direct/indirect dichotomy (or continuum) is a misapprehension of how language works. All communication is indirect in some sense because we don't have mind control powers over our fellow humans. Even saying ‘I want to buy this bread’ is indirect in a sense: you're not causing the baker to sell you the bread, nor even explicitly instructing them to, but just stating your personal internal desires. It is a cultural construct that being told someone's internal desire is supposed to function as a ‘direct’ instruction to satisfy it, and even in that there is a lot of room for ambiguity depending on context etc. For example, if I were speaking not to the baker but to my friend as we peruse the bakery together, ‘I want to buy this bread’ could have a variety of intended impacts on their actions. It could mean ‘let's come to an agreement about whether we should collectively buy this bread’. It could mean ‘pass me my wallet so I can pay for the bread’. It could mean ‘go and find me a shopkeep who can legally sell me the bread’. It could just mean ‘you are my friend and I'm telling you my internal monologue so that you can understand me better’.<p>If you interpret the language of a different culture (separated by space or time — try reading the ‘flowery’ language of Victorian or Elizabethan literature) too literally, it reads as ‘indirect’. But that doesn't mean that the native speakers from that culture consider it so. You're simply missing the cultural context that makes <i>their</i> phrasing as ‘direct’ to them as ‘I want to buy this bread’ is to you.</p>
]]></description><pubDate>Sat, 14 Mar 2026 17:07:21 +0000</pubDate><link>https://news.ycombinator.com/item?id=47378739</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47378739</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47378739</guid></item><item><title><![CDATA[New comment by Twey in "I beg you to follow Crocker's Rules, even if you will be rude to me"]]></title><description><![CDATA[
<p>> Are you implying other people's emotional immaturity is exclusively my problem to solve?<p>Emotional maturity (from most standpoints) does not mean being completely emotionally unaffected by other people's communication. Insofar as it is emotional immaturity that gives rise to a particular emotional response it might be ethically that person's duty to work on it, if that's how your personal ethics works. But from a pragmatic perspective if you want to get something done that involves that person as a colleague or collaborator it's probably not going to be productive to continually bash your head on their psychological quirks until they go to therapy. You'll have much more luck adapting your own communication to be more aligned with their needs, regardless of how reasonable you personally think those needs are.<p>If you can't or don't want to put in the effort to do that your other option is to make sure you surround yourself with people who can already communicate effectively and relatively comfortably in the communication style you consider natural. You can cut off relationships, move jobs, or fire people to purge everyone else from the circle of people you have to interact with. But you'll be missing out on all the positive contributions of those people, who probably bring viewpoints alien to you, and you run the risk of sycophancy. Plus you'll have a harder time finding people to date/collaborate with/employ/… if you restrict your pool that way.<p>In practice I think people tend to end up somewhere in the middle of that spectrum. They'll decide a maximum investment of energy they're willing or capable of putting into accommodating other people's needs, and make sure that work × time doesn't exceed that threshold.</p>
]]></description><pubDate>Sat, 14 Mar 2026 16:51:23 +0000</pubDate><link>https://news.ycombinator.com/item?id=47378546</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47378546</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47378546</guid></item><item><title><![CDATA[New comment by Twey in "I beg you to follow Crocker's Rules, even if you will be rude to me"]]></title><description><![CDATA[
<p>Sometimes what you're trying to get them to do is understand something that you (think you) understand.<p>There's a reason software has tutorials as well as reference documentation. Sometimes telling someone something directly isn't as effective at getting them to understand it as explaining it more slowly or obliquely. Sharing <i>your</i> learning journey to arrive at the understanding is (one possibility for) presenting a working path to understanding.<p>It's also the case that, especially when someone's knowledge diverges a lot from your own, it may not be obvious to them what information is relevant to you — and it may even be surprising to you. As an extreme example, there was a bug where OpenOffice wouldn't print on Tuesdays [1]. This happens a lot with non-technical users, but can also happen with other technical people who don't have the same level of understanding of a particular subsystem (in both directions — if you understand it better they may not know what information is key to understanding its behaviour, and if they understand it better they may not realize what information they're taking for granted that you don't know — e.g. the famous joke about ‘monads are just monoids in the category of endofunctors, what's the problem?’). As I've spent more time in technical discussions I've got better at homing in on the information I need — but I can't materialize information that wasn't given to me in the first place. So I'd rather people shotgun information at me than narrow it down to just the one point that they think is relevant.<p>[1]: <a href="https://bugs.launchpad.net/ubuntu/+source/cupsys/+bug/255161/comments/28" rel="nofollow">https://bugs.launchpad.net/ubuntu/+source/cupsys/+bug/255161...</a></p>
]]></description><pubDate>Sat, 14 Mar 2026 15:58:15 +0000</pubDate><link>https://news.ycombinator.com/item?id=47377957</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47377957</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47377957</guid></item><item><title><![CDATA[New comment by Twey in "The Isolation Trap: Erlang"]]></title><description><![CDATA[
<p>Message passing is <i>a type of</i> mutable shared state — but one that's restricted in some important way to eliminate a certain class of errors (in Erlang's case, to a thread-safe queue with pairwise ordering guarantees so that all processing on a particular actor's state is effectively atomic). You can also pick other structures that give different guarantees, e.g. LVars or CRDTs make operations commutative so that the ordering problems go away (but by removing your ability to write non-commutative operations). The big win for the actor model is (just) that it linearizes all operations on a particular substate of the program while allowing other actors' states to be operated on concurrently.<p>Nobody argues that any of these approaches is a silver bullet for all concurrency problems. Indeed most of the problems of concurrency have direct equivalents in the world of single-threaded programming that are typically hard and only partially solved: deadlocks and livelocks are just infinite loops that occur across a thread boundary, protocol violations are just type errors that occur across a thread boundary, et cetera. But being able to rule out some of these problems in the happy case, even if you have to deal with them occasionally when writing more fiddly code, is still a big win.<p>If you have an actor <i>Mem</i> that is shared between two other actors <i>A</i> and <i>B</i> then <i>Mem</i> functions exactly as shared memory does between colocated threads in a multithreaded system: after all, RAM on a computer is implemented by sending messages down a bus! The difference is just that in the hardware case the messages you can pass to/from the actor (i.e. the atomicity boundaries) are fixed by the hardware, e.g. to reads/writes on particular fixed-sized ranges of memory, while with a shared actor <i>Mem</i> is free to present its own set of software-defined operations, with awareness of the program's semantics. Memory fences are a limited way to bring that programmability to hardware memory, but the programmer still has the onerous and error-prone task of mapping domain operations to fences.</p>
]]></description><pubDate>Sat, 14 Mar 2026 15:36:06 +0000</pubDate><link>https://news.ycombinator.com/item?id=47377738</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47377738</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47377738</guid></item><item><title><![CDATA[New comment by Twey in "Malus – Clean Room as a Service"]]></title><description><![CDATA[
<p>They certainly have the right. All laws are (effectively?) public in every country I can think of, even when the law is ‘don't upset the not-so-benevolent dictator’. The problem is that to try to cover all the corner cases the sheer amount of law in effect in rule-of-law countries is too much for any one human to realistically consume, and that's before getting into the various _interpretations_ of the laws given by case law, precedent, etc. Any ‘plain-language’ explanation would be a) still gigantic and b) wrong in new and exciting ways — this is why the entire profession of ‘lawyer’ exists.<p>To make this more practicable you might be able to drastically narrow the context of the information, e.g. to the current task. So you could have an app that watches everything you do and tells you if you're (possibly) about to break a law. The extreme version of this looks like wearing a body camera at all times and having a little ‘voice of the state’ in your ear that tells you what your legal options are on every circumstance. Maybe a little dystopian, especially if it starts reporting you if you don't follow its guidance.</p>
]]></description><pubDate>Sat, 14 Mar 2026 14:58:11 +0000</pubDate><link>https://news.ycombinator.com/item?id=47377348</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47377348</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47377348</guid></item><item><title><![CDATA[New comment by Twey in "Malus – Clean Room as a Service"]]></title><description><![CDATA[
<p>The problem with precise law enforcement is that the legal system is incredibly complex. There's a tagline that ‘everybody's a criminal’; I don't know if that's necessarily true but I do definitely believe that a large number of ‘innocent’ people are criminals (by the letter of the law) without their knowledge. Because we usually only bother to prosecute crimes if some obvious harm has been done this doesn't cause a lot of damage in practice (though it can be abused), but if you start enforcing the letter of every law precisely it suddenly becomes the obligation of every citizen to know every law — in a de facto way, rather than just the de jure way we currently have as a consequence of ‘ignorance of the law is no excuse’. So an increase of precision in law enforcement must be preceded by a drastic simplification of the law itself — not a bad thing by any means, but also not an easy (or, perhaps, possible) task.</p>
]]></description><pubDate>Thu, 12 Mar 2026 18:28:02 +0000</pubDate><link>https://news.ycombinator.com/item?id=47355140</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47355140</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47355140</guid></item><item><title><![CDATA[New comment by Twey in "λProlog: Logic programming in higher-order logic"]]></title><description><![CDATA[
<p>Nice link, thank you! I'm not sure it's super related to my comment but it is closely related to some other things I'm thinking about. I'll give it a read :)</p>
]]></description><pubDate>Mon, 09 Mar 2026 05:30:15 +0000</pubDate><link>https://news.ycombinator.com/item?id=47305195</link><dc:creator>Twey</dc:creator><comments>https://news.ycombinator.com/item?id=47305195</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47305195</guid></item></channel></rss>