HNHacker News
TopNewBestAskShowJobs

crdrost

3,621 karma · joined January 22, 2019

Email via [my HN name] at the Google email site.
submissionscomments
crdrost··on BioTerrorism Will Save Your Life with the 4 Thieves Vinegar Collective [video]
You two are in a battle over aesthetics, it is a battle that neither of you can win.

There is something attractive about a new set of work gloves. They are fresh, clean, almost begging you to use them in a project.

There is something attractive about a set of work gloves that have curled to the shape of your hands and have been burnished by sap and sawdusts and oils: come on old friend, let's remake our previous magic.

There's something nice about a fleecy throw, but they are not as cozy as the quilts my wife made for my daughter, but defining that coziness will remain out of reach as far as my words go.

No one can be correct, here. It's just what appeals more or less to you.

crdrost··on Gukesh becomes the youngest chess world champion in history
Honestly this sounds like a knock-on effect of the US's constant erosion of the glue of community. Church attendance down, sport attendance down, theater attendance with friends down, it's all the same.

Social norms can change this -- the Netherlands has a very similar culture to the US, But one thing people asked me while I was doing my M.Sc. there was just, "what is your sport?" ... and I got asked it enough that I eventually got one, and then for a good period of time I managed to completely kick my obesity, until I moved back to the American Midwest.

The introvert/extrovert axis also plays a role in what sort of "sport" is right for you, of course, and many of your sophisticated friends still hit the gym or jog etc. -- those are just sports for introverts in my view.

Sport time is not, time that could have been better spent elsewhere. It's like how cleaning the sink isn't time that could have been better spent elsewhere -- if you don't have a clean sink, you'll pay the interest in terms of "ugh what's that smell [...] oh it was the standing water in this bowl" and "crap I don't have a clean glass, hm, I wonder if I can just buy compostable cups on Amazon so that I don't have that problem..." etc. So as an extrovert, I can go once a week to play soccer with friends in a small league, or, just hear me out, I can get lonely and then do what I do when I get lonely, which is pop on Physics Stack Exchange and answer physics questions so that I can feel Of Use. You pay the interest either way.

Chess-time also is no great loss for the world. The top-level world chess community is something we have numbers for -- 17k titled players, 2k grandmasters, 4k international masters beneath that. They are pursuing something that exactly fits the nerdy way that their brain works -- memorize openings out to 20 moves deep, obsessively study and re-study their failed games to understand why the computer thinks they lost and how they might make better mistakes in the future, and for them it HAS to be competitive and they HAVE to have that immediate feedback of trying a new idea in the same narrow niche of ideas that they became a super-expert-in, against another top player who can punish their new mistakes.

It's just not a set of transferable world-changing skills. It's like, my brother became single-mindedly obsessed with pool in High School. This persists even though he now runs a small company operating a strip mall. This was just his thing, he loves that there is no upper bound to how much control he can have over the cue and the balls, using the spins of each to control the layout, and precisely planning a course through a 9-ball break and setting himself up for a clean sweep through the game. There was no world in which some "world-changing create-the-future" lifestyle, would have felt as much of a glove fitting his hand to him, as this did. And it is no great loss for the world that he found the glove that fits his hand. It's not like the strip mall would have become an American retail empire rivaling Amazon, if only he had spent his nighttime hours working on the mall instead of on his life passion.

For comparison, probably most of the people in the bottom 10% performance bracket at Google are being told and pressured "you need to do more, more, more, you're gonna get fired if you keep those low numbers up" and at 180k employees, that amounts to 18k people that, unlike top chess players, probably _could_ flourish and do better in some smaller scrappier company, but because America doesn't have a social safety net to speak of, they feel like "well I got the dream 6-figure job, I better hold onto that until my knuckles are white because if I got fired, Bay Area rent and cost-of-living could bankrupt me in 3 months." And that's literally just one megatech company, not even talking about the world of people Graeber argues are doing "bullshit jobs" etc. etc.

crdrost··on Boltzmann brain
It's philosophically gauche but I often like to criticize arguments based on “what if they were right?”...

So for example the ontological argument putatively argues for the existence of a Perfect Being but it would seem to work even if you restricted the domain somewhat to something smaller than “all beings”, and so presumably also argues for the existence of a perfect Toaster.

Similarly here, the claim is that in a BB universe, even though countlessly more brains see the exact same stuff as you, there is something about the Bayesian update factor that you all have where you all still should conclude you are not the Boltzmann Brains and the evidence is never enough.

How do you look at that description, and not conclude that according to that argument, Bayesian reasoning is just strictly wrong? Like everyone (more or less) is “it” and everyone (more or less) says “it’s not me!” and everyone (more or less) is wrong and here is our philosopher dusting their hands saying ‘yep! sounds good, solved the problem!’

crdrost··on A liar who always lies says "All my hats are green."
> What the author would probably say is “All my hats are green” means the liar is either lying about All or Green. Either all their hats are some other color or only one hat is green. This means you have to assume the liar has a hat. How do we know that?

This is almost certainly not what the author will say, and it does have some tangential connections to computing so it's worth expanding on briefly.

In computing you often reduce problems to smaller problems, this can be done with recursion but it doesn't have to be, dynamic programming kind of is the reverse of it; whatever. When you do that though, you get these questions about really small collections, sets, lists, data structures.

Just for a quick concrete example so that we're not an abstract theory land, is a one-element list sorted? Is a zero element list sorted? Is [5, 5, 5] sorted ascending, descending, both, or neither? If you choose the wrong answer, then it means that your algorithm needs to be more complex, you don't trust zero-element lists to be sorted so your quicksort HAS to pivot on a median of 3, you don't trust one-element lists to be sorted so your quicksort HAS to pivot on a median of 5, or maybe when you see that you would recurse into a list of size 1 you generate a new median-pivot or something.

In mathematics, there is a convention which attempts to generalize this idea that an empty list is always sorted. In fact, an empty list is also always randomly sorted. It is always sorted descending, too. If it's an empty array of ints, all of those ints are greater than 1000—and they are also less than 50.

The mathematical convention is, in lay speak, “if you are talking about nothing, pretty much anything you say is going to be true unless it's gibberish.” If I said every int is green, well, synesthesia excepted ints don't really have colors, that's crap.

Everything else is “trivially true.” More formally, any predicate of the form {for all elements in S, this is true of that element} is taken to be “trivially true” when S is an empty set. It is something like the code,

    let agg = true
    for (const element of mylist) {
      agg = agg || f(element)
    }
where no matter what f is, if mylist was empty, agg is true. (“Trivial” here is sometimes replaced with the word “vacuous” because “trivially” is also a common English word meaning “easily,” so something “trivially true” might also by normal English rules mean “is easily seen to be true, is easily proven to be true, we can debunk the opposite with a 5 second look at the Wikipedia page,” etc.)

So that's the convention and besides making base cases much easier, one reason to do this is that the negation of any “for all Xs in the set, Y” is always perfectly specified as “there exists an X in the set such that not-Y.” The other convention you'd have to negate as “Either the set is empty or (...)”.

So the claim is that the perfect Liar is lying according to mathematical rules of Truth and falsehood, and according to those rules, this statement “all of my hats are green” can only be false if there exists at least one hat belonging to the liar which is not green. If there are no hats then the statement was trivially true.

crdrost··on The Rules of Programming (2023)
If we mix Polish and Hungarian notation we get Buda notation:

    flowingSequence :: (a -> [x]) -> ((a, x) -> y) -> (a -> a -> a) -> [a] -> [y]
    flowingSequence = lyla''aaa'ypax_lxa where
      lyla''aaa'ypax_lxa lxa ypax aaa la = map ypax $ concatMap (lpax_palx . palx_a) la2 
        where
          la2 = scanl1 aaa la
          palx_a a = (a, lxa a)
          lpax_palx (a, lx) = map pax_x lx
              where pax_x x = (a, x)
(The Treaty of Buda was a political maneuver that briefly created a united monarchy for Hungary and Poland in the 1300s.)
crdrost··on Grifters, believers, grinders, and coasters
Thanks! For me 2x2 is a lumber grade.

And yes, I agree, I am trying to exclude a large class of 2x2s. I don't consider "false positive, false negative, true positive, true negative" as a more insightful classification of the four quadrants than just saying "test=positive condition=negative" etc., and the point of such a diagram is not to tell a story to your management. (In this particular case it's usually to point out that by making the test more or less stringent, you have a tradeoff between false positives and false negatives.)

Similarly, a 2D graph can also be used to depict a cost-benefit analysis for a bunch of different options, to try to emphasize "I think this is a low-cost high-benefit remediation strategy compared to those other strategies", I don't regard this as a "proper" 2x2, it's just a persuasive tool.

crdrost··on Grifters, believers, grinders, and coasters
Yes! So Alan Kay points out in some of his many videos that we enjoy sitting around a campfire and talking with our friends, but if we run the numbers, we get more retention from reading and also reading is considerably faster, which makes me a little more willing to take the time to write something up.

In theory text-to-speech is a significant accelerator even though I'm a touch-typist? I haven't found an AI that can actually properly mirror my style and hit the basic points that I'm interested in in a way that I can say "eh, close enough."

crdrost··on Grifters, believers, grinders, and coasters
No. Cynefin flow is always along one axis at a time. You wouldn't invert both at the same time.

As for why it is a part of my definition of what makes such a diagram "correct" (as opposed to 4 random labels applied to irrelevant axes), it's kind of because that's the only interesting story that can be told in those 2 dimensions?

So suppose you had an hourglass shape of flow; then if you conditionally invert one of the axes (invert y when x is negative) you get a conventional cynefin flow. So if you were faced with a case where intense idealists were turning into coasting pragmatists, it suggests that you would want to just choose a different axis for one of the sides. Say you wanted to keep idealism-vs-pragmatism, but now you have to describe something that's "intense work if you're an idealist, but coasting if you're a pragmatist." And you might call that "mission work" or "evangelism" or something, acting out your most fundamental values. If you choose that as your axis, the one side inverts and the hourglass becomes a conventional fourbox (or 2x2 as a comment above calls it).

crdrost··on Grifters, believers, grinders, and coasters
In addition to people being multidimensional, this sort of diagram usually has a sort of "internal motion" to it.

That is, this is an instance of a diagram that you'll see repeated over and over in business texts; I personally call it a "fourbox" but I suppose "business matrix" is more common and "quadrant analysis" or something like that is even more descriptive. The idea is that you identify two different things, graph those as separate axes, label the quadrants and then tell a story about the four different labels. The Eisenhower matrix is the usual example (one axis is how close is the deadline, near vs far, the other is how much is lost by missing the deadline, a little vs a lot. The immediacy is called "urgency", the stakes are called "importance," things that are important-and-urgent should be done by you now, things that are important-not-urgent should be scheduled, things that are urgent-not-important should be delegated to someone else, and everything in the last quadrant should be safely ignored).

A "true" fourbox in my view should tell a particular story, which I call "cynefin flow" after a different iconic fourbox that told this story compellingly. According to this flow, there should be motion in a circle about the center of the axes, except that it gets interrupted at one transition between the quadrants and becomes stuck in a U-shape, unless some outside stimulus pushes it over that edge. So there is a motion I -> II -> III -> IV around the quadrants but then things get stuck in IV unless an outside stimulus pushes it back into I.

The cynefin story for the Eisenhower matrix ends with things getting stuck in not-important-not-urgent, so that is your IV quadrant. Of the two stories you can tell from there, the more compelling story is that, "Things that are important but not urgent, become important-and-urgent as the clock runs down, but then the deadline will pass and the pain becomes a sunk cost and they become unimportant-and-urgent, only to eventually fade to being unimportant-and-not-urgent, until an external stimulus acts to suddenly attach additional stakes to them and make them important again." So you have a bill (I), that bill comes due (II), you miss the deadline but still have a chance to pay it (III), and finally it gets sent to collections and impacts your credit (IV). And it sits there until either the debt expires or you're trying to get a new house, in which case it becomes Important again (I) to clean up your credit history.

Similarly with the BCG matrix, which is a fourbox with your capture of a market on one axis, the market's growth rate on a separate axis. Then the businessfolk carefully write "cash cow, question mark, star, dog" on each of these four quadrants. But what makes it a true fourbox is that your "question marks" that you invest in become "stars" as you capture their markets, then become "cash cows" as growth dries up, then become "dogs" as the market itself stagnates, until some external stimulus creates the opportunity for growth and more question marks again.

OP's diagram has "work intensity" on one axis, and a sort of "idealism-vs-pragmatism" axis for the other, and they have identified the intense pragmatist as naturally falling under a Cynefin flow into being a coasting pragmatist as they burn out. Presumably this is the accumulation point and those are the III and IV of the system, in which case some external stimulus causes coasting pragmatists to become coasting idealists, at which point they will naturally become intense idealists as their aspirations come to the fore, and then naturally become intense pragmatists as the organization fails to reward their idealism?

crdrost··on Every board game rulebook is awful [pdf]
Ironically these two comments seem to indicate a guide to technical writing, that did not view technical writing itself as a technology which they were writing about?

Like, should start with a "quick start overview" about here's how the process looks, etc.?

crdrost··on You can use C-Reduce for any language
One nice thing is that, once it's in your shell history, doing it again is really easy. So on a big codebase I was working on, it really did help multiple times and saved more than the initial investment.

The frustrating thing is, because it's in your shell history, you have to look it up again after you change jobs...

crdrost··on You can use C-Reduce for any language
Yes! The actual commands that you have to search up to get it to run automatically without user input, take almost as long to put together as finding the bug that you're finding (in the 80% case, of course there are 20% cases that take forever) but there is something so satisfying about seeing the thing just humming along once you have it set, that just makes it so satisfying.
crdrost··on Functional Programming Self-Affirmations
Also to mention it, languages without discriminated unions often have generics and function types, which can be used to build discriminated unions with Church encodings:

    // idiomatic typescript
    type Optional<IfAbsent, IfPresent> = 
     | {type: 'absent', detail: IfAbsent}
     | {type: 'present', value: IfPresent}
    
    // Church-encoded version
    type Either<x, y> = <z>(ifLeft: (x: x) => z, ifRight: (y: y) => z) => z
    
    // isomorphism between the two
    function church<x, y>(opt: Optional<x, y>): Either<x, y> {
      return (ifLeft, ifRight) => opt.type === 'absent'? ifLeft(opt.detail) : ifRight(opt.value)
    }
    function unchurch<x, y>(opt: Either<x, y>): Optional<x, y> {
      return opt<Optional<x,y>>(x => ({type: 'absent', detail: x}), y => ({type: 'present', value: y}))
    }
In addition the Church encoding of a sum type, is a function that takes N handler functions and calls the appropriate one for the case that the data type is in. With a little squinting, this is the Visitor pattern.

    interface LeftRightVisitor<X, Y, Z> {
      visit(x: Left<X>): Z
      visit(y: Right<Y>): Z
    }
    interface LeftRight<X, Y> {
      accept<Z>(visitor: LeftRightVisitor<X, Y, Z>): Z;
    }
    class Left<X> implements LeftRight<X, any> {
      constructor(public readonly x: X) {}
      accept<Z>(visitor: LeftRightVisitor<X, any, Z>) {
        return visitor.visit(this)
      }
    }
    class Right<Y> implements LeftRight<any, Y> {
      constructor(public readonly y: Y) {}
      accept<Z>(visitor: LeftRightVisitor<any, Y, Z>) {
        return visitor.visit(this)
      }
    }
    // isomorphism
    function visitify<X, Y>(opt: Optional<X, Y>): LeftRight<X, Y> {
      return opt.type === 'absent' ? new Left(opt.detail) : new Right(opt.value)
    }
    function unvisitify<X, Y>(opt: LeftRight<X, Y>): Optional<X, Y> {
      return opt.accept({
        visit(value: Left<X> | Right<Y>) {
          return value instanceof Left? {type: 'absent', detail: value.x} : {type: 'present', value: value.y}
        }
      })
    }
The main difference with the usual visitor pattern is that the usual visitor pattern doesn't return anything (it expects you to be holding some mutable state and the visitor will mutate it), you can do that too if you don't have access to a suitable generic for the Z parameter.
crdrost··on Functional Programming Self-Affirmations
Approximate expansion of the original claim, without direct endorsement:

Suppose you have an Order object that needs to track where some larger process is in relation to three subtasks. We could imagine say that the Inventory department needs to set a physical object aside, then the Billing department needs to successfully charge for it, then the Shipping department needs to retrieve that physical object and ship it.

You start from a description of this as "one Order contains three Subtasks" where a Subtask contains the Go-style (Optional[Result], Optional[Error]) type. This architecture almost fits into a relational database, except that foreign key constraints are a bit funky if you shove everything into one nullable Result column. But let's just have the Result be some random JSON in the Subtasks table and let our relational purists weep.

Then you read this advice and you start to see that this allows for a lot of illegal states: things could contain both a result AND an error, or neither. You eventually decide that neither, is an allowed state. These are two boolean flags representing only 3 legal states and so they need to be factored into an enum: the enum is "Pending | Success[Result] | Failure[Error]".

Well, except the problem is a bit more nuanced because the pending-states also need to be consistent among the different subtasks: there is a dependency graph among them. So you should actually have an enum that says:

    Inventory_Pending
    Inventory_Failure[Error]
    Inventory_OK_Billing_Pending[InventoryData]
    Inventory_OK_Billing_Failure[InventoryData, Error]
    Inventory_OK_Billing_OK_Shipping_Pending[InventoryData, BillingData]
    Inventory_OK_Billing_OK_Shipping_Failure[InventoryData, BillingData, Error]
    Inventory_OK_Billing_OK_Shipping_OK[InventoryData, BillingData, ShippingData]
See, you would have had 3x3x3 = 27 valid states before for the Order but we have reduced to only the 7 legal states. Yay!

But now consider e.g. the following mutation. On Failure cases the executives at our company mandate that we never return a failed Order to a Pending status, rather we must always create a separate Order. This Order might skip inventory and/or billing and those need to be represented separately, as Inventory Skipped[OrderID] or InventoryAndBillingSkipped[OrderID]. So now our list of states following the "no unrepresentable state" logic, should really be:

    [... the 7 above, plus ...]
    Inventory_Skipped_Billing_Pending[OrderID]
    Inventory_Skipped_Billing_Failure[OrderID, Error]
    Inventory_Skipped_Billing_OK_Shipping_Pending[OrderID, BillingData]
    Inventory_Skipped_Billing_OK_Shipping_Failure[OrderID, BillingData, Error]
    Inventory_Skipped_Billing_OK_Shipping_OK[OrderID, BillingData, ShippingData]
    Inventory_And_Billing_Skipped_Shipping_Pending[OrderID]
    Inventory_And_Billing_Skipped_Shipping_Failure[OrderID, Error]
    Inventory_And_Billing_Skipped_Shipping_OK[OrderID, ShippingData]
Now someone else wants to add remediation actions, but only to remediate the exact error in the failure state, so _Failure is going to mean "no remediation taken" but we need to add some _Remediation with a boolean saying whether that process has completed or not. So we add:

    Inventory_Remediation[Error, Bool, Array[RemediationEvent]]
    Inventory_OK_Billing_Remediation[InventoryData, Error, Bool, Array[RemediationEvent]]
    Inventory_OK_Billing_OK_Shipping_Remediation[InventoryData, BillingData, Error, Bool, Array[RemediationEvent]]
    Inventory_Skipped_Billing_Remediation[OrderID, Error, Bool, Array[RemediationEvent]]
    Inventory_Skipped_Billing_OK_Shipping_Remediation[OrderID, BillingData, Error, Bool, Array[RemediationEvent]]
    Inventory_And_Billing_Skipped_Shipping_Remediation[OrderID, Error, Bool, Array[RemediationEvent]]
We're only up to 21 total states so far which is still probably manageable? But these changes do demonstrate exponential growth, which is a technical term that means that the growth of each step is some small fraction of the total growth that has happened up until that point. Because everything depends on Inventory (it's at the root of the tree), when we add a new state that the Inventory can be in (Skipped) we have to add enum cases for all of the other states, and we pay a cost proportional to the size of the tree. Similarly when everything can have an error (at the leaves of the tree), when we add a new uniform requirement for errors we have to add new leaves all throughout the tree and we pay a cost proportional to the size of the tree. (Another thing to notice about the Remediation state is that it is a Pending state for another Subtask that could have been added to the original Order whenever something moves into Failure mode.)

You get something powerful by reducing the 256ish-or-whatever states into the 21 legal states; you have a compile-time assurance that no bugs in your code have created weird states that can propagate their weirdnesses throughout the system. But you also have to maintain the 21 legal states all at once, instead of maintaining 4 subtasks each having one of 4 statuses.

crdrost··on Dear sir, you have built a compiler (2022)
There is also the opposite, Ed Kmett is on record as saying that he had a million ideas for his personal programming language, and all of the cool stuff it was going to do, but then he ran into Haskell and said “Let’s be real, whatever amazing language I make isn't gonna be half as put together as this and I have this one already in front of me...”
crdrost··on Dear sir, you have built a compiler (2022)
I'd mostly agree. SPAs can do things hard to do with URLs and form inputs; for instance, chess would be harder to program in the browser without JS (though I remember an opening explorer which worked that way). Or if you think about popping up a modal or a toast. But a lot of the functionality is duplicated.

This gets even more extreme now that you can have wasm on a canvas... The language that you're compiling from doesn't understand the semantics of a back button either!

crdrost··on The letter ℘: name and origin? (2017)
We solved that though, it's now pronounced “(h)aitch-bar-o-mega.”
crdrost··on Why is it so hard to find a job now? Enter Ghost Jobs
Yes, this is precisely what the comment thread is saying. Shmatt’s original post should shock you with its conclusion because everyone loses including shmatt.
crdrost··on Trump wins presidency for second time
I get that, probably if I got you talking to my "dead gummint" friends you'd talk past each other about the word "damaging", they'd say "that's not damaging at all, what are you smoking?" etc. etc.

Just to be clear, what you need to understand if you want to bring them back Right is that for them "damaging" is defined by "someone shows up with a gun at your house and tells you to do something that you don't want to do." Amazon can do whatever, precisely because the people who Amazon sends to your house, like they might have a gun if they're practicing open-carry, but they don't tell you to do anything that you don't want to do. They literally cannot define any damage that Amazon is doing by manipulating their marketplace, because Amazon's not sending out the Men With Guns.

And just to be clear, again, I don't agree with my friends on these matters, I just find it absolutely fucking nuts that back when I was a hardline conservative I made these friends and now that I'm moderate and independent somehow they are the ones that I'm seeing supporting Kamala and the Democrats.

crdrost··on Trump wins presidency for second time
Just to be clear, are you saying that the ACLU has not been pissed off at the GOP for book bans? Or are you just saying they should be mad at Amazon more?

(Because like, libertarians and the ACLU are not going to get mad at Amazon for deciding what rules they want to enforce in their own marketplace. Which makes me read your comment as just another instance of shouting “fuck the libertarians!” that I above called a phenomenal waste of conservative resources. Like, why? There shouldn't be this strange alliance between the “only government that can be trusted is a dead government” people and the fucking political Left, like, WTF if that’s what’s going on)

crdrost··on Trump wins presidency for second time
One irony atop another: securing this land (against the onslaught of big business) was a celebration for Conservatives, not Liberals.

That and, I miss the Republican party that didn't actively try to piss off the ACLU every hour on the hour. It's just nonstop…

• book bans • rhetoric about sending the military after political opponents • politicians ruled as being above the law • short circuiting due process with immigrants, both illegal and not • breaking up families of would-be asylum seekers for no damn reason • the Trump Muslim ban • the constant erection of/for Ten Commandments statues

It used to be a thing in some conservative circles, “No, that teacher is Northern Conservative Baptist Great Lakes Region Council of 1912, not Council of 1879, I don't want his people educating my child about what he thinks the Ten Commandments really mean!!”

I used to fancy myself a conservative back then. The ACLU and libertarians were the people that the Left had kind of given up on, and we were happy to say “yes, come be conservative with us, and we will try not to piss you off.” Now everyone has given up on them, they had to hold their noses and vote Kamala and pray for a few more years of “not again.”

I'm not even a libertarian, just don't understand why we are wasting resources pissing them off

crdrost··on Ternary Operators
So I want to clarify that I don't think you're wrong, I just think that that's like saying + is a ternary operator because of course x +^{n} y, which is x plus y n times, and therefore equal to x + (n × y), has three symbols that are related by the terms.

When I called this out you started talking now about something a bit different, partial derivatives, which accept two integer indices and not just one. But behold, the symmetrical version of +^n is +^{m, n}, such that

    x +^{m,n} y = m x + n y.
It’s not that any of this is wrong, ya dig? Just that we're counting to three to feel satisfied when there isn't much satisfaction to be gained.
crdrost··on Ternary Operators
On the one hand the n'th derivative operator is clearly a binary operator that you are composing with a function application operator.

On the other hand, OP seems to have not noticed that the ternary conditional also has this structure. That is, `f : x` could be syntactic sugar for `f(() => x)` [or perhaps `f(p => p, () => x)` if you like Church encodings] and then there are a few options for meanings of `x ? y` that have `(x ? y) : z` as a conditional.

crdrost··on Company named "><SCRIPT SRC=HTTPS://MJT.XSS.HT> LTD" forced to change it (2020)
That advice is 90% because developers are lazy. Like we'll write

    const csv = rows.map(cols => cols.join(','))
                    .join('\n')
because we are too lazy to write the more correct,

    const esc = cell => `"${String(cell).replace(/"/g, '""')}"`
    const csv = rows.map(cols => cols.map(esc).join(','))
                    .join('\n')
(And perhaps something slightly more efficient but slower that only quotes each cell when it needs to be escaped.)

I caught myself doing it the other day, Go has a JSON library and here I was too lazy to define a struct,

    w.WriteHeader(500)
    fmt.Fprintf(w, `{"error": %q}`, err.Error())
Is %q a JSON-compatible format? I have no idea without reading some source code! Almost certainly it won't \u-encode weird characters. That might be OK, I think the only stuff you really have to escape in JSON strings is newlines, backslashes, and double quotes? And %q probably handles those. Maybe it breaks on ASCII control characters...

But yeah, we are meant to always use a library because we have deadlines and we are willing to compromise a whole lot of quality to deliver on them.

crdrost··on The useful use of cat
That's the point is that it's up to the shell to make sure that you don't use your work if you do the wrong thing. Could be as simple as prompting you to make sure -- "Overwrite <filename>? [yn]: " -- or could be something where the old inode is still available under some magic path for a few more commands, or could be that you use special syntax for the command, like "@<path>" is the stdin/stdout command form for the path... or it could be something else entirely, really.

For an instance where there are thousands of bash scripts out there that work around a case where `abc >file` does not work, consider the times when you want to write to a file which you don't have write permissions to, with sudo. my favorite way to do this is with `tee` but I have also seen others: but `>file` is not one of them! Because it's emphatically not part of the algebra of the rest of the shell; the rest of the shell is written in pipes, this one command says "I'm going to make your pipeline terminate, this step will be un-pipeable."

For another example where the algebra doesn't consistently handle the whole system, consider that in a normal language you would consider writing a function which returns a value and also prints debug logs to the process's stdout. Bash can't do this on its own, you have to figure out which /dev/tty is attached to the process and then write your debug log to that TTY, and then your script probably fails in interesting ways when it itself is redirected to a file and there is no TTY that it is attached to anymore...

crdrost··on Time is a dimension, but not like space
Yeah normal time units still exist in relativity, clocks gotta clock.

But ratber it's that there exists an operation which is almost entirely like rotation, but it rotates x, y, or z into w=ct, where w is measured in meters just like x,y,z are, but t is measured in time units, and c is the speed of light converting between them. Instead of a rotation's formula with sines and cosines like

    x' = x cos θ + y sin θ
    y' = y cos θ – x sin θ
    (x')² + (y')² = x² + y²
relativity has a slightly different set of functions sinh and cosh that are very closely related to sin and cos. (Sine and cosine have Taylor series where the polynomials alternate, sin(x) = x – x³/6 + x^5/120 – ..., and sinh and cosh have the exact same Taylor series with all + signs rather than alternating + – + –.) The analogous expressions are then,

    w' = w cosh φ — x sinh φ
    x' = x cosh φ — w sinh φ
    (w')² – (x')² = w² – x².
This transformation, in relativity, is just built into how any acceleration works. So whenever you accelerate, even in pre-relativistic physics, you expect to see the emergence of some Doppler shifts. In relativity these shifts are not quite as strong as expected from the classical theory, and as a result when you subtract off the Doppler shifts and try to say "what has happened" you get an answer that "the meaning of the present moment, which historically defined a 3D universe frozen at a point in time, identifies a different 3D slice of the 4D spacetime." And this is what "rotates", it's the rotation of the plane that you think is the "present moment".

The fact that you are discretely "you" about ten times per second, I am taking as a fact of biology. But if you try to convert that biology into physics, that's where you convert t into w to get that t=0.1s converts to w = 30,000 km.

crdrost··on The useful use of cat
The problem is that according to this argument `cat` should never be used for the thing it was designed for, because if you use it with more than one argument, it would give most Unix users pause, but if you saw it with only one argument they would understand it instantly.

The whole point of the "never use cat" Unix advice is a war between instrumentalism and design purism. Should things be known mostly for what they're useful for, or mostly for what they were made to do? If you understand this, then the war is not soluble but you can at least phrase a third position that will reconcile both sides. If you don't understand this, then the war is over an issue that doesn't even exist.

Hot take: `<file> | abc` and `abc | <file>` should both make sense because a file should be understood by default as a command that reads from and writes to a particular destination, and the shell should take it seriously that `abc | <file>` needs to be easily undoable if the file wasn't chmodded +x appropriately.

crdrost··on Time is a dimension, but not like space
It kind of is that (a metaphysical restatement), but it's more precisely understood as a kind of half-statement of the theory.

That is, if you assume relativity, then for anything which moves faster than speed c, there exists some reference frame where it appears to move backwards in time. (This needs to be slightly qualified because it's kind of like when you're looking in a mirror and you intuitively don't think it does what it actually does -- flip front to back -- but you mentally rotate and then think that it flips left-to-right. So to be clear, if someone on a hyperluminal rocket cracks an egg into a pan, there exists someone else whose best understanding of this situation is a rocket that is traveling "backwards" engine-first, onboard of which an egg is flying up from the pan into an eggshell. But you would mentally reorient to say that the rocket is traveling "forwards" and that "forwards" direction is backwards in time.)

Now, this doesn't directly violate causality by itself, it depends on whether you can move faster than light according to an arbitrary observer. So if Carol goes faster than light according to Alice and then turns and goes faster than light according to Bob, and Bob is moving relative to Alice, only then can Carol potentially meet up with her "past self" according to Alice & Bob. The idea is that the first time she moves, Alice says she's moving very fast, but forward in time, and Bob says she's moving backward in time. Then the second time she moves, Bob says she's moving very fast, but forward in time, and Alice says she's moving backward in time. You combine these two to find that both agree that she has objectively moved backward in time.

The way this manifests in the mathematics is that in relativity, after something happens, light kind of "announces" that it happened to the rest of the world, via an expanding bubble of photons traveling away from the event at speed c. This expanding bubble is formally known as a "light cone". There is another light cone as well: before the event happens you can understand a contracting bubble of photons traveling towards the event. And basically these partition the world into five regions: The contracting bubble is the "objective past" of the event, that bubble itself is the "null past" of the event, the spacetime between the bubbles is the "general present" of the event, the expanding bubble is the "null future" of the event, and the points inside of the bubble are the "objective future" of the event. Moving faster than light, is moving from the objective future of an event, into its general present. This is "general" because different reference frames regard these points as either before or after the event in time. You need a second trajectory to then go from the general present of the event, to its objective past.

crdrost··on Time is a dimension, but not like space
You have understood it about as well as the article did!

Now, there is a huge nuance here, which is that you are moving near the speed of light, to certain observers. This is like the whole "relativ-" prefix in "relativity", you are at rest in your rest frame, you are moving very fast in some other rest frames. The cosmic muon crashing into Earth, sees you as time-dilated! So with that nuance "we experience time at nearly the speed of light" just becomes kind of a tautology like "we experience time how we experience time."

But a better way to think about this is, you are about two meters high, you are about a meter wide, about a half-meter dorsoventrally... and about 30 000 000 m in the other direction, if we're looking at the human reaction time/blink-of-an-eye range of 0.1s (think about how 10fps video is at the cusp of being continuous and how 20Hz is where clicks stop sounding differentiated and instead start sounding like a bass note).

What this means is that if we look at you relativistically, you kind of look like a big "rope" with worldlines of other atoms coming in, braiding into your body, eventually leaving... but the strands of this rope are bundled into these cells that have worldlines over 99.9999% parallel. (Atoms within those cells move faster, but you're probably at least 99.999% parallel even if we make that statement?) And that astonishing parallelism is precisely why relativity is not very intuitively plausible to us.

crdrost··on An illustrated proof of the CAP theorem (2018)
So, when it was originally phrased, the primary thing that you would have learned about databases, was that they enable ACID transactions. (And if you were a practitioner you would have learned about the various isolation levels and dirty reads and dirty writes.)

But if you wanted to go from this level to implementation, typically you could get a prototype working, but it would be slow. When things are slow, the WD-40 of the programming world is to add a cache. And this is where you get the quip that there are only two hard problems in computing, cache invalidation and naming things. (The “and off-by-one errors” is a later addition.) The problem is that cache invalidation shows up as consistency bugs in your database. Someone does a rare combination of commits and rollbacks and some cache doesn't get wiped quite as fast as it needs to, or is wiped overoptimistically causing a pull from uncommitted data, and your isolation level has dropped to READ UNCOMMITTED.

The CAP theorem was originally raised as a conjecture, something like, “once you shard the database, I don't think there's any way to solve these cache problems without one of the replicas just going silent for arbitrarily long pauses while it tries to at least partially synchronize its cache with the other shards.” Phrased that way, you can understand why it was a conjecture, it relies on nobody at MIT having a super clever way to deal with caches and cleverly routing the synchronization around the sharding.

BUT, you can make that statement for many different reasons, and this was not for Pedagogical Reasons, its point was rather Evangelism! The author was attempting to introduce the idea of Eventual Consistency, and gain adoption by ditching all of the wisdom about ACID transactions. This antagonism was deliberate, eventual consistency became the E in a rival acronym BASE. And so the argument was that we could explore a new corner of design-space.

It was later that someone decided they could prove it by coming up with a universal subgraph, “whatever connection you've got, it has to contain this: two nodes, fighting over one value, with a network connection possibly passing through other nodes but we can abstract all that away.” And then you have a proof, and then you have a bunch of people comparing the proof to the stated claims of various database vendors, and finding that over and over they claim to be both shardable with high availability among the shards, and to support ACID transactions that keep everything consistent. It turns out those statements are usually made assuming a happy path!

(You also get Paxos and Raft, “here is how to get consistency without arbitrary latency on two-phase commit via majority vote”, and the Jepsen blog “you said this had consistency level X, let’s fuzz it and see if we can generate a counterexample”, and some interesting exceptions like Datomic saying “this one part is not scalable and it's a single point of failure to sacrifice P for the CAP theorem’s sake, but in exchange we can simplify our C and A guarantees so that you can scale the reads of the system consistently.”)

← PreviousPage 4 of 26Next →