Hacker Newsnew | past | comments | ask | show | jobs | submit | hathawsh's commentslogin

I try to remember to say something like this: "This is an interesting solution, but I'm not confident we have a shared understanding of the problem we're solving. I have a few guesses, but I don't want to bias the discussion, so please restate the problem without suggesting a solution. If it's too difficult to explain, I can suggest what problems I think you might be running into." I wish I always remembered to say that. :-)


Until you run into that most stubborn, "my problem is the absence of this solution" type of stakeholder...


Upper management material right there.


"The cat is out of the bag" doesn't mean the cat is gone, it means the cat has freedom. I read the GP as meaning "no single company can currently control the trajectory of AI." That's not unfortunate -- that's great!


No, doesn't mean that either.

People would sell piglets and would try to sell "a pig in a poke" (where a poke is a bag).

That's why you don't buy a pig in a poke because you can't see what you're buying.

Letting the cat out of the bag is because you've revealed that it was a cat rather than a piglet. You've revealed the deception.


Thanks for the correction. In my own words, to commit to memory: once "the cat is out of the bag", the point is not that it's difficult to put the cat back in, the point is that we now know it's a cat and putting it back is not relevant.


I've seen two expressions referring to "it's difficult to put the (thing) back in" that are in more-or-less common use in English. The slightly more common one is "You can't put the genie back into the bottle", and the slightly less common one (in my experience, at least) is "You can't put the toothpaste back into the tube." (Which actually inspired me to try, and it is actually possible to put the toothpaste back into the tube with careful application of suction, by squeezing the tube gently, touching the end to the excess toothpaste, then releasing the tube and letting some of the excess get sucked back in. But I digress.)

I've actually seen the "genie back into the bottle" phrase used in contexts that refer to secrets, e.g. where "the cat is out of the bag" would actually be more appropriate, so there's definitely some overlap there. For example, I've seen people talking about nuclear proliferation say "you can't put the nuclear genie back into the bottle", meaning that the secret of how to build a nuclear weapon is well-known, and it's not really possible to make it secret again. But I've also seen people use the same "you can't put the nuclear genie back into the bottle" expression referring to a nuclear weapon exploding: once the radioactive material in the bomb has gone critical, there's nothing anybody can do to stop the explosion that's about to happen.

Personally, I like the "genie back into the bottle" phrase better. But some people like more grounded-in-reality phrases rather than fantasy-based phrases, and they prefer "toothpaste back into the tube". Either one works well, though.


I think I have to commend you for trying to put the toothpaste back in the tube. These expressions are more or less some form of fatalism and when used in political context it is very annoying. Especially when some politicians are working there asses off to make something claimed inevitable happen.


Last time I joined a discussion about US health care on HN (years ago), the picture looked bleak: secret chargemasters in every hospital, no realistic way for patients to compare options because the options are too complicated, and lots of people still falling through the cracks.

I can't help but think the picture looks very different now. There is growing awareness that chargemasters can not be secret. LLMs offer a way to overcome the complexity of choosing options, opening doors for real competition. I sincerely hope we can take advantage of this changed landscape to provide better care. Universal health care remains an interesting possible direction, but I now have hope that we can do a lot better within the existing laws.


That's fantastic. I have long, winding trails near me also and one of these days I also want to start prompting a coding agent on my bike with a headset. Do you recommend any particular type of headset?

Edit: never mind, I see you already suggested the Shokz OpenComm2 in another comment. Thanks!


This is so alien to me. Why not plug into the machine matrix when out in the great outdoors enjoying sublime nature? Why not!


It's not a replacement for being outdoors, connecting with nature. It replaces indoor desk bound office work.


Iroh looks very interesting!

How current is the PyPI package? https://pypi.org/project/iroh/


We bumped to 1.0 an hour ago https://pypi.org/project/iroh/#history


If I were doing a code review, I would probably accept the code either with or without the assertion. The context of curl_getenv() makes it clear that null is not acceptable. If the author of curl_getenv() had evidence that callers are frequently breaking the contract by passing null, then perhaps the assertion would help shed some light on violators. Otherwise, I would expect everyone to play by the rules, making the assertion unnecessary.


It's also just a wrapper around getenv that provides consistent behavior across platforms, and passing a NULL name to the POSIX getenv function is UB.


That is exactly why you have a precondition or assertion.

If everyone expects specific behavior - ie it’s in the contract - you require that contract.


The problem with asserts is that they are pretty dramatic and you crash the entire program.

We generally did this in the avahi libraries, be fairly liberal with asserts that "shouldn't happen", it is a source of complaints though because basically you can be using a third party library that uses avahi and have your program crash due to a bug in that library, or in avahi. It's extra fun when using some historical libc systems such as "NSS" and you load a plugin to do hostname resolution, which nss-mdns does.. now you can have any program on the entire system crash if you are assert happy.

On the one hand I agree that if the result is going to be memory un-safety then perhaps you should assert, but more ideally you'd just fail gracefully and throw or return an error. That can sometimes be tricky though, if there is no good way to return an error or return a NULL value or similar. Depending on the API.

Of course, this is the entire reason behind the error return traditions of Golang and Rust, e.g: https://doc.rust-lang.org/book/ch09-00-error-handling.html

Which basically says what I said above :)

But in the case of curl_getenv, returning NULL seems a valid possibility (https://curl.se/libcurl/c/curl_getenv.html) as that is indicated to be done if you don't find the requested environment variable. Arguably the NULL environment variable is not found. so, this feels likely to be acceptable. Though I could see an argument for you now assuming the environment variable you were actually looking for not existing, but you didn't actually ask for one, and now your logic is broken and maybe you introduce a different class of security bug because you change your behaviour based on some environment variable not existing.

As always everything is a trade-off...


Returning to the context of this post, this is one of the things I really like about rust. (And zig, haskell, typescript, swift and others). These languages make invalid states impossible to represent. If my function takes a value of type T (or &T), you can't accidentally receive NULL. So you just don't need to worry about this stuff any more. The compiler simply won't compile the program if type checking fails. At runtime, I only have to consider valid values.


Zig still doesn't have a way to represent that a pointer to a heap allocated region is no longer valid.


Crashing a program is always a much better alternative than behaviours that silently lead to memory corrupt, having much severe outcomes than a crash.

Ah but what high integrity computing, well there neither crashes nor memory corruption are welcomed, hence programming guidelines and certification workflows that would make most C devs cry with the language features they are allowed to use, and how each line of code gets analysed by tools and humans.


Yes, but null pointers are so pervasive in C code that we really can't afford to put assertions everywhere. It's often better to let the app crash on violations.


An assertion is an app crashing on a violation. The problem is when it's not guaranteed to crash, and instead does something very wrong.


A bug is a bug even when it doesn't clearly manifest itself 100% of the time, and furthermore it is pretty much guaranteed that NULL dereference crashes with segfault in practice, only not for the people playing theoretic games whose essence of life is finding gotchas where it maybe isn't so and then feeling smarter than everyone else.

But it's >> 99.9% true that this will just crash even though it's acshually UB, nasal demons and so forth. Now raise this << 0.1% likelihood that it isn't true on some system with some compiler and build flags, to the power of the number of distinct deployed configurations out there, and you get the result which is the correct engineering decision of just moving on instead of spending your life filling straightforward code with pointless boilerplate assertions.

NB it can make sense to assert nonnull when the condition won't be tested on all code paths or the intention is otherwise not super obvious.


> it's >> 99.9% true that this will just crash even though it's acshually UB, nasal demons and so forth.

Is it though? Linux saw enough bugs from that kind of issue that they now build with -fno-delete-null-pointer-checks and accept the (supposed) performance penalty.


The kernel is perhaps bit special. In the past they had bugs such as first derferencing and then checking for null and weird possibilities to map the zero page. But today I am not convinced this is really needed.

In general on a system where you trap when accessing the zero page, this optimization should be safe and a null pointer dereferences should (safely) trap.


> In general on a system where you trap when accessing the zero page, this optimization should be safe and a null pointer dereferences should (safely) trap.

If you mean that C compiler writers "should" prioritise sanity over high scores on microbenchmarks, then I agree. However in practice they do not and this optimization is not remotely safe.


Do you have any evidence for this? On GCC it should be safe.

(EDIT: what is not safe is indexing into a null pointer. For this you need to be safe you need -fsanitize=null)


I don't understand your comment - dereferencing a null pointer is unsafe, in the sense that it does not reliably crash but may do other things, as we saw in the kernel case we're talking about. Yes that particular case was only exploitable if you mapped the zero page, but given how all-bets-are-off a situation it created (where extremely experienced programmers thought they knew what the code did, thought it was safe, and were wrong), I would not want to count on all cases not being exploitable without mapping the zero page.


May. If. If. If. In case.

We are talking about an extremely simple straightforward API with an obvious contract. It's good enough for this function to reliably surface almost all wrong uses with a segfault immediately. Wrong use will result in segfaults and otherwise bugs and crashes. The goal is not to work when used wrong but to work when used right. You cannot save the world from scratch in every little function. You still have a job to get done, and you have to move on.


> You cannot save the world from scratch in every little function. You still have a job to get done, and you have to move on.

Or you can take all of 10 minutes to put sanity-check assertions at the start of all your public-facing API functions, eliminating a source of security bugs, get on with your life, and worry about the performance implications as and when it becomes a problem (hint: it's never going to become a problem).


You can try and do this if it's a relatively narrow public facing API, but otherwise this is a theoretic ideal. In practice, if you add an assertion for every pointer argument to every little function, you'll go insane, and it is completely pointless, and the code will not be readable anymore.

There are so many other interesting and relevant invariants that are usually in an API contract that are much harder or impossible to check upfront (let alone express formally in a type system), and even violations may be impossible to diagnose when they happen.

People focus on NULL because that's the only way they can apply their silly limited type systems. But NULL checks give very little return for investment. In practice, you'll see templated Option<T> types and whatnot, and when I have to look at or even work with such code I want to kill myself because it's so painful.


No, people focus on a handful of things like null, buffer overrun, and use-after-free because they still make up the majority of security vulnerabilities that we see exploited in the wild. You may imagine that subtle logic errors are more common, but the data doesn't bear that out; also FWIW I've never seen one of these detailed invariants be impossible to express in a type system if you spend 5 minutes actually trying.


Typical invariant for me would look like:

Given a, b, c input parameters to my func, it must hold that that a->m->t == b->t. c->mutex must be held, and c->cond is the condition variable that goes with c->mutex and will release any waiters on the buffer contained in a.

Or: Integer x is representable using 12 bits only, Integer y should be a multiple of N and I have a integer s is used as a bit-shift that should be less than 8.

Or: I need to guarantee that no locks have to be taken and no allocations have to be made on this complicated looking codepath. While holding a lock, we must not do any syscalls (syscall a, b, c are ok though), and surely not make any logging calls.

I know only one system that can express this, it's called STRAIGHTFORWARD CODE, and it requires doing engineering and casual logic out-of-band, and yes it does include making mistakes and repairing them incrementally.

I don't know a type system that would let me explain these things to me and tell me where I was wrong. But maybe you can show me, with 5 minutes of actually trying?


> it must hold that that a->m->t == b->t.

So define a wrapper type that represents that invariant (it's not going to take up space at runtime), where the only constructor enforces it?

> Integer x is representable using 12 bits only, Integer y should be a multiple of N and I have a integer s is used as a bit-shift that should be less than 8.

Those are all standard things that already exist?

> Or: I need to guarantee that no locks have to be taken and no allocations have to be made on this complicated looking codepath. While holding a lock, we must not do any syscalls (syscall a, b, c are ok though), and surely not make any logging calls.

Sounds like a pretty standard free monad case? Define a command algebra in which the "ok" syscalls are a subtype, and then require that the thing you want to only use the ok calls to have a type that reflects that?


Please, go ahead and type the example. I think you are trolling.

> Define a command algebra in which the "ok" syscalls are a subtype

Dude, it's clear you're not doing any actual work. You are living in an ivory tower, and you underestimate the complexity and detail and volatility of real world applications by at least 3 orders of magnitude. You don't understand how to modularize and contain complexity.

You _cannot_ complete a project with this attitude.

You are ignorant of the fact that a type system is necessarily a blunt simplification of the real complexity. Therefore, use of types must be pragmatic, and actual logic must be coded in normal code (which should be obvious but it isn't to type theory weirdos). Otherwise, you require dependent typing or whatever, and you will have to write your code twice, once in a usable programming language and once in a very unusable programming language. Much more than only twice actually, given that all the implicit detail should apprently go explicitly formalized at the type level.

Just to make sure I'm not entirely talking out of my arse because I'm so incredibly annoyed by your otherworldly proposition, I asked an AI about the sel4 microkernel. It consists of 10,000 lines of C code (that says a lot about its practical utility, which is very limited), and of 1,3 million lines of manually written proof code (which says a lot about the practicality of proving).


It takes a lot longer to figure out if it'll be a problem than to just add the check. And you don't have to ponder whether it's possible for a null to get there, because now it's fine if it does.


Are you talking about extending the API contract to allow for NULL? That is often the path to madness, especially if it requires complicating the signature (return value etc). Better to just assert/crash.


No. I'm talking about adding the check to reject NULL. Then you don't have to spend time justifying or figuring out why a NULL can't turn up here.


So reject as in assert? But how does that go together with what you said, "because now it's fine if it does"?


Because no one is expecting it to work if a null is passed. Your total range of behaviours left are crashes, doesn't crash and is silently ok, or doesn't crash and causes something worse (data corruption, you get your product in a CVE, that area).

My proposition is that "it's silently ok" isn't likely enough, which is in line with your position on "don't extend the contract to accept null". So what's left is crash, or something worse.

So if those are your choices, don't waste time justifying that a null can't get there, just add a check to ensure you get the better behaviour. It takes seconds.


If you follow that line of reasoning, you will end up testing almost every pointer before accessing it. The reason is that you are extending your valid state space massively since you aren't able to specify "this subset of 7 trillion distinct states is invalid, if it was the case we would have failed before".

You are requiring yourself to find a valid outcome for an input that doesn't make _any_ sense in the context of what your application is meant to achieve. How is that not a Sysiphean task?


You're not "extending" the valid state space. That null value being passed to that function is already a potential state of your program.

You're actually pruning the valid state space; before, when the null value is passed to the function, there are more operations performed that have uncertain consequences. If you assert-and-fail when you get the null input, you've pruned those states.


So if I understand correctly now, you _do_ proclaim to put asserts, not write code that somehow copes with the "possiblity" of NULL.

"Because no one is expecting it to work if a null is passed", so you can do whatever. If you write an assert for every pointer passed to every function, that will be a lot of asserts, for pretty much the same outcome in practice. Asserts are just marginally more ergonomic when they trigger, but are a nuisance in the code often. So my position is to use them judiciously, but not overdo it, be instead focused on the actual task.

When the lack of non-null assertions is an actual problem during development, you have much larger structural issues.


Yes. The work to assert each pointer passed into a function isn't "high"; it's purely mechanical, it could almost be refactored automatically. But most of all, the effort required to prove you don't need to is _way_ higher.

I don't want to nitpick people often but your use of division sign to mean percent is really throwing me off.


Thanks for letting me know, nitpick appreciated. Typing on my phone.


An assert is not guaranteed to terminate the process. In C, the most common implementation choice is to completely omit the check if you're not building in debug mode.


You need to turn it off by defining NDEBUG. While sometimes it is not for release builds, I am not sure this is common.


Visual Studio defaults to defining NDEBUG in release mode, and I think that default was pretty influential


When I tell my coworkers to stop using AI to dress up their words, it's not because I care about human effort. The problem is that my coworkers often start with incorrect assumptions, and AI is good at amplifying bad assumptions and making them sound plausible. I have to spend extra time guessing at what the author originally wrote and then address the partly-hidden original points rather than what the AI generated. Give me your spelling errors, your grammar, your mumbles, your incoherent streams of thought, your doubt and uncertainty. Those things are extremely important, yet your robot obscures them.

Strangely, I've also observed that some customers respond very well to words dressed up by AI, even if the words oversimplify the truth. Now I'm working to understand why they want that. Are my customers not swimming in AI slop like the rest of us?

BTW, this doesn't mean I'm anti-AI. AI coding is an incredible superpower and I use it constantly, but it seems to me that AI coding works because code expresses the minutiae that is rightfully omitted from most other communication.


Sorry to break it to you, but on that timeline, the good things got poisoned. IBM enhanced Lisp with Enterprise Ready features like Spreadsheet Macro Builder, Microsoft took over development of Smalltalk and morphed it into BASIC 2.0, and the HURD community lost a bizarre copyright lawsuit. Fortunately for those folks, an intrepid hacker in the 90s saw some of the interesting ideas in MS-DOS and rebuilt it as LS-DOS. Today, most of their servers and mobile phones run LS-DOS or similar.


LSD-OS would be an AI core unsupported by runtime and operating system that cascades streams of consciousness in a portable cartridge smartphone form factor until mounted on an embodiment to become unified and coherent.


Ah. A common (and understandable) misconception. LSD-OS doesn’t enhance anything in the UX, it just removes the filters that prevent you from seeing reality, man.

Some confuse this with LDS-OS, which makes the user weirdly and unquestionably `nice` by only accepting inputs from protected mode.


Your HN account is too new for me to be sure whether you're being sarcastic or not. Perhaps you know, or perhaps you don't, that all code is machine-translated, even assembly language. None of it is perfect, but it's not garbage. Today's AI merely provides a new level. It's a weird, non-deterministic level, but hiring an employee to write code for you is similarly non-deterministic.


Right, and that's why Mel was a true programmer!

Seriously though, that's an overly-pedantic definition of a compiler. Broadly speaking, languages compile in a direction of decreasing abstraction. Crossing from one high-level abstraction to another is just asking for trouble, especially in this case where the target language makes very specific performance promises as long as certain abstractions are maintained.


These are also the markers of human journalists who write daily. Journalism is the reason AI acquired these habits. Gemini says this article is probably not generated by AI, particularly because it has original quotes.

https://gemini.google.com/share/ba48849a15a9


Personally I wouldn't cite Gemini for this because I have no idea if it has any kind of track record of accurately distinguishing human from AI writing.

That said, Pangram agrees and its track record is pretty good.


> particularly because it has original quotes.

I'm not saying the quotes are fake, that would be horrific. I'm saying the rest of the article appears to have had minimal human intervention.


At some point, however distasteful to the naturalists, do we accept that writing with AI is still writing? There will be an arms race the way there was moving from banner ads -> whatever hellscape we have today ...


It's the same as copying and pasting the wikipedia article and calling that your article. We all can generate our own slop if we want. If all you are peddling is slop, you are peddling nothing I can't get myself.


Then why did you point to the em-dash in the quote as evidence of AI authorship?


LLMs did not invent clickbaity headlines. Kinda odd that people think it did


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: