HN user

munch117

485 karma
Posts3
Comments283
View on HN

The fatal flaw in PG's argument is that is doesn't mention spending at all.

If you're spending your entire income on things like food and rent, then a 1% wealth tax corresponds to 0% income tax.

If you're spending your entire income on investment, then there's a calculation like PG's to be made to compute an equivalent income tax rate. But then we're talking about someone who doesn't need the money. This isn't even about rich vs. poor - you can have a high income and spend it all as you make it, like if you throw a huge party every week, or make a yearly trip into space. But if not, then it's just an ever growing number on your bank statement, and the only reason you care about it being 20% higher is because you're comparing it to other people's bank statements.

I didn't suggest that implementations should entirely eliminate every form of UB. There is plenty of middle ground. For example, you could easily limit the consequences of integer overflow by specifying or partially specifying overflow behaviour, with very little runtime cost.

I'm not suggesting you change how you write code, but with a better implementation the code that you do write - that lives in the real world where mistakes are made - might work better. How is that being pedantic?

An interesting case where compiler writers did something like that is casting via union members, but I'm running out of time, so we can talk about that another day.

Both are wrong. It means "this standard does not constrain the behaviour of code that does this".

It's entirely legal for implementations to have predictable behaviour, documented or not, for code that is undefined by the standard. In their quest for maxxing benchmark performance they generally choose not to, but there's really nothing in any standard that stops you from making an implementation that prioritises safety.

Making a plan that works for the general case, but is also efficient, is rather trivial. Here's pseudocode from spending two minutes on the problem:

    # INPUT: lookfor: unicode
    var lower, upper: ascii
    lower = ascii_lower_bound(lookfor)
    upper = ascii_upper_bound(lookfor)
    for candidate:ascii in index_lookup(lower .. upper):
        if expensive_correct_compare_equal(candidate.field, lookfor):
            yield candidate
The magic is to have functions ascii_lower_bound and ascii_upper_bound, that compute an ASCII string such that all ASCII strings that compare smaller (greater) cannot be equal to the input. Those functions are not hard to write. Although you might have to implement versions for each supported locale-dependent text comparison algorithm, but still, not a big deal.

Worst case, 'lower' and 'upper' span the whole table - could happen if you have some really gnarly string comparison rules to deal with. But then you're no worse off than before. And most of the time you'll have lower==upper and excellent performance.

Just clearly state your requirements.

Nothing new here. Getting users to clearly state their requirements has always been like pulling teeth. Incomplete sentences and all.

If the people you are teaching are developers, they should know better. But I'm not all that surprised if many of them don't. People will be people.

TNG, by a country mile. B5 has "writer identifies too much with the main character" written all over it. It's the story of how Our Great Leader does the right thing and saves the world, over and over again.

I was reading https://www.offsec.com/blog/cve-2026-24061/, which implies that precisely that single long string passes through getenv("USER") in the attack. The mystery is how that single long string in telnetd becomes two separate arguments for login. execv or posix_spawn certainly won't do that. So either there's a version of /usr/bin/login that parses arguments in some very sus way, or there's a shell involved somehow.

I'm slightly taken aback by the telnetd fix: The solution to the username "-f root" being interpreted as two arguments to /usr/bin/login is to add a "sanitize" function, really? I'm not seeing the sense in that. Surely in any case where the sanitize functions changes something, the login will fail. Better to error out early than to sanitize and try to hobble along.

What I'd like to know is how the arguments get interpreted like that in the first place. If I try giving that kind of argument /usr/bin/login directly, its argument parser chides me:

  $ login '-f root'
  login: illegal option --  
What's telnetd doing differently? Is it invoking login via a shell?

Also worth noting that the author never actually stated that they did not use generative AI for this article.

I expect that they did in some small way, especially considering the source.

But not to an extent where it was anywhere near as relevant as the actual points being made. "Please don't complain about tangential annoyances,", the guidelines say.

I don't mind at all that it's pointed out when an article is nothing more than AI ponderings. Sure, call out AI fluff, and in particular, call out an article that might contain incorrect confabulated information. This just wasn't that.

I struggled a bit with what to point to as signs that it's not an LLM conception. Someone else had commented on the headlines as something that was AI-like, and since I could easily imagine a writing process that would lead to headlines like that, that's what I chose. A little too confidently perhaps, sorry.

But actually, I think I shouldn't have needed to identify any signs. It's the people claiming something's the work of an LLM based on little more than gut feelings, that should be asked to provide more substance. The length of sentences? Number of bullet points? That's really thin.

This article is just about as un-AI written as anything I've ever read. The headings are clearly just the outline that he started with. An outline with a clear concept for the story that he's trying to tell.

I'm beginning to wonder how many of the "This was written by AI!" comments are AI-generated.

A __del__ that does any kind of real work is asking for trouble. Use it to print a diagnostic reminding you to call .close() or .join() or use a with statement, and nothing else. For example:

    def close(self):
        self._closed = True
        self.do_interesting_finalisation_stuff()
    def __del__(self):
        if not self._closed:
            print("Programming error! Forgot to .close()", self)
If you do anything the slightest bit more interesting than that in your __del__, then you are likely to regret it.

Every time I've written a __del__ that did more, it has been trouble and I've ended up whittling it down to a simple diagnostic. With one notable exception: A __del__ that put a termination notification into a queue.Queue which a different thread was listening to. That one worked great: If the other thread was still alive and listening, then it would get the message. If not, then the message would just get garbage-collected with the Queue, but message would be redundant anyway, so that would be fine.

If you think you disagree with him (as I once did), please consider the possibility that you've only been exposed to an ersatz characterization of his argument.

My first exposure was a video of Searle himself explaining the Chinese room argument.

It came across as a claim that a whole can never be more than its parts. It made as much sense as claiming that a car cannot possibly drive, as it consists of parts that separately cannot drive.

Ah, I missed that 9.a-c were alternatives. And that, in the absence of custom tables or functions, they are merely defense in depth for something that is already secure, barring bugs. I withdraw my concern.

I'm not that concerned with bugs in sqlite. sqlite is high quality software, and the application that uses it is a more likely source of vulnerabilities.

But I do see a problem if you really need to use a sqlite that's compiled with particular non-default options.

Say I design a file format and implement it, and my implementation uses an sqlite library that's compiled with all the right options. Then I evangelize my file format, telling everyone that it's really just an sqlite database and sooo easy to work with.

First thing that happens is that someone writes a neat little utility for working with the files, written in language X, which comes with a handy sqlite3 library. But that library is not compiled with the right options, and boom, you have a vulnerable utility.

Thank you for making this.

I have an idea for a gameplay that I think I would enjoy more:

  - If the first guess is within a factor of sqrt(10), then you win.
  - If not, you are given two choices for the second guess: Up or down.
  - Up and down are 10x higher and lower guesses (making them adjacent ranges to the first guess).
  - If the second guess is wrong, you lose. No more guesses.
The point is that the second guess makes you rethink the original question once more, to figure out what it was that you missed. Which is more fun that doing bisection.

I wrote 10x and sqrt(10) to make a game literally about orders of magnitude, but you could of course you smaller numbers, like 4x and sqrt(4), to make it harder.

Not only that, the compiler's optimizer might actually do a better job if you split up a big function. Because the smaller functions have less register pressure.

What does this sentence even mean?

Apologies for my non-native English. I'll try putting more words on it and maybe it will come out less convoluted.

It's easier to eat a lot of salad when it's finely cut. Then you just shovel in a portion with a bit of everything with every grab of the fork or spoon. With a large piece of lettuce, you need to cut it first, and then stab the piece with the fork, and then combine with other ingredients. Which makes eating that kind of salad a slow process. That's what I meant by "suited for slow nibbling of token amounts".

It is precisely a salad for people who don't generally eat salads.

The big uncut leaves are suited for slow nibbling of token amounts of salad.

Croutons are recognizable from a distance as a non vegetable ingredient, making it attractive to someone who'd rather not eat vegetables at all. To me they're just stale bread.

Agreed. To do accounting, you need to employ some kind of discipline to ensure that you get rounding right. So many people erroneously believe that such a discipline has to be based on fixed point or decimal floating point numbers. But binary floating point can work just fine.

FP does not introduce imprecision. Quite the contrary: The continuous rounding (or truncation) triggered by using scaled integers is what introduces imprecision. Whereas exponent scaling in floating point ensures that all the bits in the mantissa are put to good use.

It's a trade-off between precision and predictability. Floating point provides the former. Scaled integers provide the latter.

The answer is accounting. In accounting you want predictability and reproducibility more than anything, and you are prepared to throw away precision on that alter.

If you're summing up the cost of items in a webshop, then you're in the domain of accounting. If the result appears to be off by a single cent because of a rounding subtlety, then you're in trouble, because even though no one should care about that single cent, it will give the appearance that you don't know what you're doing. Not to mention the trouble you could get in for computing taxes wrong.

If, on the other hand, you're doing financial forecasting or computing stock price targets, then you're not in the domain of accounting, and using floating point for money is just fine.

I'm guessing from your post that your finance people are more like the latter. I could be wrong though - accountants do tend to use Excel.

Postel's law isn't about accepting arbitrary invalid inputs. It's about inputs that are technically invalid but the intent is obvious from looking at it, and handling those according to intent.

In a distributed non-adversarial setting, this is exactly what you want for robustness.

The problem, as we've come to realise in the time since Postel's law was formulated, is that there is no such thing as a distributed non-adversarial setting. So I get what you're saying.

But your definition of robustness is too narrow as well. There's more to robustness than security. When Outlook strips out a certificate from an email for alleged security reasons, then that's not robustness, that's the opposite, brokenness: You had one job, to deliver an attachment from A to B, and you failed.

Robustness and security can be at odds. It's quite OK to say, "on so and so occasion I choose to make the system not robust, because the robust solution would not be sufficiently secure".

Then what happens, if you're that type of person, after you've replaced or painted over something? Do you relax and become comfortable with what's left? Or do you move on to the next irritant, that will bug you until you've replaced or painted over that?

I saw some pictures from a house where everything was white. The walls were white, the tables and chairs were white, the pillows were white, lamps were white, etc. But I bet the owner didn't see it as everything being white, like I did. I bet that when they'd look at the same pictures, they'd see all the little details here and there that were not white, or not quite white enough. I imagine them being in a constant state of stress over the non-white blemishes.

I don't know them, I just saw the pictures, so I don't truly know how they feel, I could be just imagining things. But my gut feeling is that someone with a home like that is not at ease with themselves.