Honestly with the hell I'm going through just trying to get Podman to run properly on macos, I can't imagine trusting the Podman people with a production deployment. I was not particularly impressed with the Docker tooling, but Podman has been even worse. This is a not-remotely exhaustive list of things I've run into in the last 24 hours:
* Podman fails to build a 16GB container image (after 30 minutes of downloading dependencies) despite having 90GB free out of a 200GB podman virtual machine
* Podman machine will, for reasons I don't understand, create a filesystem in a block device with wildly different sizes, and it seems like it's just random
* Pushing podman images to a container image registry via the Podman Desktop UI gives no indication that it's doing anything or even recognized the "push image" click, a success or error notification _might_ appear several or tens of minutes later or possibly not at all
* Starting a podman machine might work, but it fails ~75% of the time with not-particularly-exotic options (a bunch of ram and disk) and very cryptic error messages, frequently telling me to file bug tickets (I have)
* Podman Desktop won't let me create a podman machine with more than 44GB of disk, but the podman machine CLI won't let me create a machine with fewer than 100GB (IIRC--it's some number larger than 44, in any case)
Apart from the container image being absurdly large (Python developers love massive packages, I guess), I'm not doing anything exotic.
Kayaking, fishing, river floating, surfing, diving, snorkeling, etc. "No one I know takes their phone snorkeling" <- that's because they're not presently waterproof, but I imagine a lot of people would like to take a high quality camera under water.
I genuinely appreciated this comment—it made me chuckle. That said, I think there are better approaches to working with AI besides “here’s a big vague thing to work on, go write some code”. I think you have to iterate somewhat closely with the AI to write a doc describing exactly what you want the system to do and then scope out very narrow tickets and then have a separate agent do the TDD to actually produce the thing. The key insights here are (1) don’t let a code writing agent have too much scope—just a narrowly scoped ticket, (2) keep the coding agent’s context minimal, (3) don’t let the coding agent write much code without testing it. The agent should make very small changes at a time and then test that everything still works.
You will still need to QA stuff and review PRs, but I think AI done properly can genuinely make some tasks better.
> don’t let a code writing agent have too much scope—just a narrowly scoped ticket
it's interesting cuz my intuition is to give the language model writing the files as much context as possible, which means all of the previous planning thread. but I also thought you should plan with a small model and implement with a large one, and the meta seems to be plan with an expensive one and delegate code output to smaller ones. so what do I know.
> The agent should make very small changes at a time and then test that everything still works.
yeah I think if it's treated like a codegen machine it's basically just outputting code as if you're using a dsl, except the dsl is natural language and the output is meant to be edited, no `// this is generated code, do not edit` headers
> I think AI done properly can genuinely make some tasks better
thank god I dont need to write html by hand anymore, what a pita
Models seem to perform worse if you give them too much context. Even if you have a large context window, it seems like they’re only “smart” in the first few tens of thousands of tokens (including the system prompt, which is often huge). Also, it seems like they’re do better if you start a fresh agent off with a very narrow task and give them access to more context as necessary rather than shoving everything you have into their context window and wishing them well.
But I should also emphasize my limited experience and the rapid pace that this stuff is evolving.
TL;DR — there’s a whole lot of craft in how you use agents
I think that’s mostly true, but also I think there is some skill to using agents well. Specifically, work with agents to get a really good product requirements document, then task it out into very narrow user stories / vertical slices (this takes some iterating—the AI really seems to want to think in horizontal layers today), then maybe walk through the code interfaces to be super sure you are aligned. At each step, I make the agent interrogate me thoroughly with every question it can think of, and even if we stop now we will have a system design and tickets that are much higher quality than me thinking alone. I could hand those off to anyone to implement, but I think having an agent TDD their way through the code is the sweet spot.
Whenever the agent is doing something I don’t like (e.g., some coding style thing), I pause and have another agent help me write a style guide that agents must read. This slows me down at first but I think it will pay off in time.
I'm tempted to agree, specifically because of the depicted flag waver. That person embodies the leadership of the status quo, and nationalism is a core component of that.
Flags are literally a statement of identity, but I think that comes in two distinct flavors:
1. The national flag which is planted in a state of ownership and assimilation
2. A protest flag to state to others that they are not alone in their protest.
I could be missing something but I think it is effectively this simple.
That’s definitely not true. Unsigned ints have no “negativity” semantic. Wrapping around is what happens when you decrement the minimum value of any integer type, including signed types. Regardless of the type you use to represent an integer value that cannot legally be negative, you will have to take care not to allow your program to return values lower than zero for things like indices or sizes.
> Wrapping around is what happens when you decrement the minimum value of any integer type, including signed types.
No, signed wraparound is undefined behavior in C, whereas unsigneds are defined to wraparound. If you use -ftrapv, signed wraparound is an immediate abort().
While C like in many other places fails to define the correct behavior to avoid shaming the processor or compiler makers that fail to provide it, there are only 2 correct behaviors on overflows and underflows, like when incrementing the biggest number or decrementing the smallest number.
Both for signed integers and for non-negative integers, the 2 alternatives of correct behavior on overflows and underflows is to either generate exceptions or to saturate the result to the biggest or smallest representable number.
Wraparound is the correct behavior for integer residues, which are a distinct data type from either signed integers or non-negative integers.
While some people criticize C for making easy for careless programmers to make certain kinds of bugs, like access outside bounds, those are easily mitigated by using appropriate compiler options.
For me a much more serious defect of C is this confusion promoted by it in the heads of most programmers, who do not understand which are the fundamental integer types and which are the correct conversions between them, because C uses "unsigned" instead of at least 3 distinct types that it does not have, bit strings, integer residues and non-negative integers. More rarely, "unsigned" is used for other 2 types that are missing, binary polynomials and binary polynomial residues. All these 5 types must be primitive types in a programming language because all modern processors implement in hardware distinct operations for all 5 types, which can be accessed only through assembly language when these types are missing.
When I was building my computing stack out of x86 machine code I noticed that even if my high level language only had signed numbers (I'm still pretty brainwashed by C, which leads to the conclusions of OP), I still needed the ISA's unsigned jumps to deal with addresses (which can have the MSB set). So my big "insight" was to name unsigned comparisons "address comparisons".
This feels like you’re trying to “gotcha” me, but I didn’t say C specifies 2s complement wraparound, I said that’s what happens in virtually every language (including the major C/C++ implementations). It seems like you are “violently agreeing” with me.
That’s not a negativity semantic, it’s the behavior of the “-“ operator. If you print y or compare it to zero you will see that the result remains positive. Unsigned integers by definition have no negative semantic, hence the name.
Why does an unsigned type for sizes or indices fare worse than a signed type? When do I want the -247th element in an array? When do I have a block that is -10 bytes in size?
Because doing subtraction on sizes/indicies is common, and signed handles the case where you subtract below 0. Unsigned yields unintuitive results. i.e, unsigned fails silently. For example, looping to the 2nd to last item in an array or getting the index before the given index.
The source of confusion is that unsigned is a terrible name. Unsigned does not mean non-negative. Its 100% complete valid to assign a negative value to an unsigned, it just fails silently.
If you want non-negative integers, then you should make a wrapper class that enforces non-negativity at compile and runtime.
> The source of confusion is that unsigned is a terrible name. Unsigned does not mean non-negative. Its 100% complete valid to assign a negative value to an unsigned, it just fails silently.
C’s implicit casts are tripping you up. Unsigned ints can’t be negative, but C will happily let you assign a negative signed int to an unsigned int variable, but the moment it is assigned it ceases to be negative. In serious programming languages this implicit assignment is forbidden—you have to explicitly cast.
> For example, looping to the 2nd to last item in an array or getting the index before the given index.
I don’t understand what you mean here, can you clarify?
> If you want non-negative integers, then you should make a wrapper class that enforces non-negativity at compile and runtime.
Unsigned integers are the compile time side of the coin, but yes you may want to take care to enforce it at runtime as well, though this typically implies a performance penalty that most don’t want to pay.
In C your compiler can help you with conversions and if not, please use a better one. In this regard, C is a very pragmatic language, and hence for actual work it is a more "serious" programming language than programming languages which are based on some idealistic theory that pedantic typing will fix all your problems, but actually keep you from doing your job.
Warnings are just noise, so there's no point in printing them--they will be ignored (maybe not when there is a singular warning, but if warnings are allowed to accumulate beyond some manageable threshold). If a warning is worth printing, it should be treated as an error, and if you treat it as an error, you now are "strict" by definition.
Any reasonably good C code I ever worked with aimed to be warning free. But yes, if you can also make it an error. The flexibility is important though.
Regardless of whether you're "aiming for the code to be warning free" or telling the compiler to turn the warning into an error, you will make the implicit cast explicit and move on with your day. You've already said you should use your tools to flag these errors and that aiming to be warning free is a good thing, so I don't understand where we disagree, especially when making implicit casts explicit costs a single-digit number of keystrokes.
I was disagreeing with the statement that a "serious" language needs to have this hard-coded. think the C model where you can have the strictness if one wants to, but one can also opt-out is better.
the reason is not that you want a negative index or size, but that you want the computation of the index to be correct, and you want to have obvious errors. Both turns out to be easier with signed types.
There are (rare) times when you want negative array indices. C lets you index in both directions from a pointer to the middle of an array. That's why array indexing is signed in C. Some libc ctypes lookup tables do this. For sizing there is no strong case for negatives other than to shoehorn them into signed operations.
C23 updated the definition of the [] operator to disallow negative subscripts with array type. I think you have to explicitly convert the array to a pointer type now.
That’s interesting but seems pretty dangerous. How do you know you aren’t going to decrement off the front of the array? Keeping the pointer to the first element in the array and using offsets seems safer for humans and I don’t think the computer would care.
Kinda a smart alec response, but how do you know you aren’t going to increment off the end of the array when operating normally? I guess it is twice the danger.
You never want any element of an array, except elements within the range [0, array_length). Anything outside of that is undefined behavior.
I think people tend to overthink this. A function which takes an index argument, should simply return a result when the index is within the valid range, and error if it's outside of it (regardless of whether it's outside by being too low or too high). It doesn't particularly matter that the integer is signed.
If you aren't storing 2^64 elements in your array (which you probably aren't - most systems don't even support addressing that much memory) then the only thing unsigned gets you is a bunch of footguns (like those described in the OP article).
Let's say you have two indices into an array: a and b. You want to know how much earlier a is than b so you compute b-a, but as b was in fact the earlier one you get a negative number.
You can deal with this by casting before doing the subtraction, or you can deal with it by storing the indices as signed integers at all times. The latter is more ergonomic at the cost of wasted capacity.
Geothermal exists, but you would have to take care to design accordingly and even then there are plenty of other ways for a state actor to locate you. It probably doesn’t make much sense to spend money trying to hide from state actors; it’s probably better to (1) avoid conflict prone areas to the extent possible and (2) make it expensive for an attacker to shut you down (use more smaller data centers within a sensitive region, put some of them underground, etc) or (3) accept the risk of data center disruption.
Some Paris data centers are disguised as apartment buildings with the classic Hausmannian facade, and then you open up Google maps and see a ton of AC units stacked on the roof. These aren’t likely major cloud data centers mind you, and the motivation for concealing them has more to do with the city’s aesthetic codes than military defense.
* Podman fails to build a 16GB container image (after 30 minutes of downloading dependencies) despite having 90GB free out of a 200GB podman virtual machine
* Podman machine will, for reasons I don't understand, create a filesystem in a block device with wildly different sizes, and it seems like it's just random
* Pushing podman images to a container image registry via the Podman Desktop UI gives no indication that it's doing anything or even recognized the "push image" click, a success or error notification _might_ appear several or tens of minutes later or possibly not at all
* Starting a podman machine might work, but it fails ~75% of the time with not-particularly-exotic options (a bunch of ram and disk) and very cryptic error messages, frequently telling me to file bug tickets (I have)
* Podman Desktop won't let me create a podman machine with more than 44GB of disk, but the podman machine CLI won't let me create a machine with fewer than 100GB (IIRC--it's some number larger than 44, in any case)
Apart from the container image being absurdly large (Python developers love massive packages, I guess), I'm not doing anything exotic.
reply