Recent submissions

Comment · 5 days ago

  The judge upheld prison authorities’ argument that McKechnie had failed to provide any proper foundations for his opinion that Vegemite does not interfere with drug sniffer dogs.
What is the null-hypothesis, who is making a claim, who has the burden of proof?
Comment · 5 days ago
Comment · 6 days ago
I think the viewpoint that your're missing is: how do I make sure the machine code means the same thing as the source code?

Trying to one-shot 'print "hello world";' into

  .LC0:
        .string "hello"
  "square":
        push    rbp
        mov     rbp, rsp
  ...
is probably a non-starter, so compiler writers tend to attack the problem by breaking it down into lots of passes.

Parsing into an AST is obviously the first, then you might opt into other passes, like type-checking, handling closures, simplifying into some kind of IR, and finally generating code. Each of those stages can be effectively unit-tested (except maybe the last). If you make a mistake in parsing (e.g. mistaking a statement for an expression), you don't want to have to catch that error by inspecting machine code. It's nice if each pass can be easily tested. And one simple way to test these things is to write an interpreter for each pass (mostly because you get to enjoy the facilities of whatever host language you're writing in). Then you can start saying things like "for all inputs, interpreting the AST gives the same result as interpreting the type-checked-AST, gives the same results as interpreting the closured-AST, gives the same results as interpreting the list of IR instructions."

You mention "It ought to be easy because it is possible to only target the common subset of features these architectures support." <- That's your IR right there!

Once you have an IR that looks close enough to the target machine language, it shouldn't be too hard to translate the final step. Or just use LLVM.

I noticed in your code that you're using C, and really there's no need. Languages don't need to be stacked in a hierarchy (e.g. Clojure on top of the JVM which is C++ which compiles to asm). The compiler can be any language, because it only needs to be able to take in source code and spit out bytes.

Comment · 7 days ago
Complexity budget and all that. But I'd sooner throw out inheritance than traits.
Comment · 7 days ago
Traits/typeclasses tend to disallow your three-part scenario. It's called the orphan instance problem.

The "Goose teleports" code needs to go in Ben/Teleport.src, or Alice/Goose.src. Otherwise the compiler doesn't know which implementation to use if there are multiple.

Scala (and I think Ocaml) have mechanisms for selecting which one to use. In Haskell you'd use a newtype wrapper.

Comment · 10 days ago
I remember way back when exceeding 1.5 was in the past, not the future.

When did it become a future event again?

Comment · 10 days ago
> Revolut would own the database in my example.

If you have a protocol for interacting with your own database, you either need to rule out interacting with other systems (i.e. you have Revolut credits and you can only use them in the Revolut store,) or create a second protocol for inter-system transfers, in which case you have two protocols, and that second protocol won't play nicely with the first - e.g. partner bank informs you about a several new money transfers and a chargeback, meanwhile you're taking locks and directly setting balances. If the inter-system protocol is good enough, it will do everything the owned-locked-crud-database protocol would, and the crud is just going to get in the way.

You also have the problem of owning 'one thing'. If you lose 'one thing', you've wiped out all your records. Not to mention regular downtime from patching/releases etc. If for some reason you have the chance to use a database which presents itself as one-thing (but is distributed behind the scenes and has redundant replaceable parts) then whoever implemented that database is at the minimum using some kind of WAL (the 'ledger' of the database world), because those folks know they can't just have multiple masters CRUDding each other willy-nilly.

> How would a ledger work without having some kind of lock, how would you prevent a negative balance?

I wouldn't try to initially (but do see below). If the system can keep your balance from going below 0, then by CAP it's not available. If your supermarket loses connectivity or you're buying a cocktail while flying in a plane, your payment would just fail.

> When someone checks their balance, would you to retrieve every transaction from the ledger and calculate the current balance?

Pretty much everything in the concurrent space boils down to avoiding shared-mutable state. If you have it, your code is probably broken. Locking, ownership, defensive copies, immutability, etc. are all efforts to stay sane. If you go down the immutability path, more options open up. I use Kafka as the example. You append one new fact every time a money transfer happens. From a performance POV, Kafka scales horizontally, and appends only need negligible locking. I mention Kafka specifically because it also acts as the distribution. Different independent systems can follow it in near real-time, and they can choose to store and present the current balances, as a running calculation. And it works as long as you don't go back and edit history (corrections are appended instead.) As long as the kafka records are intact, you can always rebuild any other derived data from it.

If you did really need to forbid less than zero, you can model that in your events. Instead of emitting a MoneyMoved event, you could emit a MoveMoneyIfAvailable event. The reader of the system would see that event strictly in order (this is the key bit - you're basically using Kafka to gain linearisability in ACID-speak) and either emit a MoneyMoved event or a MoneyMoveRejected event in response. But again, this last trick doesn't mean you can order cocktails on a plane (if you tried to emit a MoveMoneyIfAvailable from up there, it wouldn't reach the server, and you also couldn't get the yes/no back anyway).

Comment · 11 days ago
I would love if it all engineers were professional enough to avoid the personal criticisms and stick to the comp sci, which is far more interesting.

This is why I wrote:

  Technical discussions are incredibly likely to devolve into people discussions.

  No people discussion has ever worked it's way back into being about fixing the broken software.
I'm perfectly happy, if things get out of hand, for someone to take me aside and say "you were a bit of a cunt back there mrkeen." We're all human. As long as we actually get fix the code or resolve the intellectual side of the argument too.

I wouldn't dream of calling someone a smug disagreeable know-it-all.

I'm here for any discussion of the tradeoffs of balance v ledger, though.

Comment · 11 days ago
Comment · 11 days ago
He suggester that they had both. My question was what to do when they disagree, and he wasn't able to either conceive of the 'two sources of truth problem' or wasn't able to suggest a solution. He pushed back saying: if they disagree then you've got buggy code, and that your job is to not write buggy code. "That's why we test". "For race conditions?" etc. etc.

Who owns the database in your locked example?

Comment · 11 days ago
I don't think you can avoid negative balance, without giving up on availability (i.e. moving from AP to CP). And then an outage like TFA takes down your whole system.

You might be assuming that there is only one database, and that all consumers are reliably connected it. So who owns the database: Visa or MasterCard? Because ACID doesn't span across database instances (let alone database vendors or companies).

If you write down that "Bob withdrew $20", that cannot be wrong, (at best it can lack info that you later wish you had).

If you write down "Bob's balance is now $10", you already know the problems with that from your question.

Comment · 11 days ago
The interviewer's job (I was briefed beforehand) was to make sure I know my concurrency, because they use a lot of it there.

I have all the patience and time in the world to discuss my ideas.

I had the problems, the solutions, slide decks and a Miro board ready to go.

He wanted to shut down discussion at every turn with nonsense like "so you think no banks work at all?". Sure, I can grin and eat shit, or I can say "banks predate your CRUD operations by just a little bit".

If he had working knowledge on how to represent mutable money amounts in a distributed environment, he didn't let on. I was all ears.

So I pushed back on him, and I'll push back on you:

> even if you were technically correct why would a company hire someone...

Because I'm technically correct.

You're certainly not alone in your appraisal of the situation. The market over here works exactly this way. Correct, reliable systems come a distant second to agreeing with the team.

Technical discussions are incredibly likely to devolve into people discussions.

No people discussion has ever worked it's way back into being about fixing the broken software.

Comment · 11 days ago
Interviewed for them this year.

Got into a heated argument where the interviewer insisted it was perfectly acceptable to store money as a mutable row in a database.

I pushed back with the standard "You append transactions (including corrections) to a ledger" but he wasn't convinced.

I whipped out the standard two-ATMs -separated-by-a-distance overdraft example, and how you can create or destroy money that way.

He said it made no sense as an example because it was buggy and you would never release buggy code.

I asked if he'd done bug fixes before (yes) but obviously he was going to keep digging in further.

The irony of it was that he was part of the blockchain team.

Comment · 11 days ago
I've been hearing about bitcoin for 15+ years and I don't think I've ever walked into a shop where they accepted it.

So, approximately six 0s of uptime for my use case?

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton