In other words, given a need for IPv4, it enables switching to mostly IPv6... seems like transition technology and reality might finally meet because both moved towards the other.
It has needed some fixing over the years. errno was one thing. There have been a number of things in that vein, where Bernstein relied upon 1989 C or even K&R semantics and suchlike.
But compared to some other code from the 1990s, it has lasted the test of time quite well.
I mean they were possibly going to help anyway or even physically closer. And I imagine that sitting around in the fire department does get boring, something to do occasionally is welcome :)
On the one hand, almost everyone (including C++ fans) agrees that the language is too big. On the other hand, comtracts just formalize an existing and useful concept.
I was thinking for implementing borrow-checker like rules for C but after I have seen what SMT solver can do I think it is not necessary to constrain the language in this way.
Yeah, the problem with the lifetimes profile vision, is the lack of acknowledgement of how MSVC and clang-tidy have struggled to achieve the Core Guidelines ideas for lifetimes (since 2015), without additional annotations.
MSVC requires SAL and clang has equally added extensions for type annotations.
The WG21 politics killed the Safe C++ proposal with the P3466 paper,
"(Re)affirm design principles for future C++ evolution"
> Do not add a feature that requires viral annotation
However it is quite clear, that without changing language semantics, for the lifetimes profile to be actually useful, as shown by MSVC and clang experience, we would need to have [[profile:lifetime(something)]] in plenty of places.
Not only would that be more verbose than what Rust and Safe C++ proposal, it would still require placing those annotations on the standard library (yet another complaint from the anti-Safe C++ proposal folks), and naturally violate the paper that was voted for as the design principles for future C++ evolution.
However in regards to how to check for C and C++ lifetime issues, at least if the source code is fully available, I have had some good experience with AI tools doing code review, like CoPilot on Visual Studio.
Maybe that is possible way forward, moreso if the code isn't being fully written by humans.
Regarding C specifically, what about having Frama-C's ACSL as some kind of ISO C annex?
Compilers would just ignore the annex and whoever wants to implement it, can already do this. And I also think ACSL is too complex for what is needed and also not well integrated with the rest of the language.
IIRC Rust's borrow checker analysis is more or less a subset of what SMT solving is capable of. It's "just" a question of tradeoffs made with respect to performance, complexity, precision, etc.
It is a really tiny and trivial subset of what model checkers can do. Model checkers can often prove memory safety of entirely unmodified C code. The problem is that this still runs into complexity problems and does not scale to non-toy programs. But this would also really be very far at the other end of the borrow checker that would require rewriting everything into a very specific form a borrow checker accepts.. IMHO a middle ground with some annotations is realistic and would be far more convenient than a borrow checker when supported by good tooling.
> The problem is that this still runs into complexity problems and does not scale to non-toy programs.
Right; that is why Rust's borrow checker was designed to be intraprocedural only. That obviously is a tradeoff of its own: now functions need to be annotated to convey information across function boundaries, and the annotations picked will influence what can and cannot be expressed.
> IMHO a middle ground with some annotations is realistic and would be far more convenient than a borrow checker when supported by good tooling.
I'd be interested in seeing what such a middle ground looks like, particularly in respect to what tradeoffs it makes!
I don't know yet. My current expectation from what I have seen is that lifetime analysis can be done fully automatic for most C code as long as it can be done independently from other program state, i.e. the checker has to reason only about the state of pointers and not also simultaneously about all other variables. I have seen quite promising work on this.
Thanks for the link! That's an interesting approach indeed. If I'm reading the paper [0] correctly the concepts involved look pretty similar to what Rust uses. I think they turn the interprocedural analysis into an intraprocedural one as well by effectively deriving borrowing information from function implementations and attaching that to signatures for use by callers. It's a compatibility hazard, which is why Rust chose to not do the same, but in principle it makes it easier to derive more precise borrowing information.
They globally derive the borrowing information for all pointers in the whole program by classifying the role of each pointer. If there is a way to do this in a way that makes the program safe, this is computed automatically using a SAT solver.
The paper explicitly says that if you use an LLM it is prompted function-by-function.
For the SAT solver I think classification can be done function-by-function if you manually drive the solver in the single-function mode, but I think you're more right in that the whole-program mode doesn't actually do that.
I think my misunderstanding stemmed from interpreting the start of section 5.4 and figure 3 as showing that constraint generation occurred strictly before the verifier was invoked and glossing over the bit at the start of section 6 that said that the process basically works the other way around when using the solver to build the p-model.
Your background is C as I understand it, and C does not really have issues with temporaries as they are known in C++ and Rust.
My understanding:
C compound literals have invariable and relatively long lifetimes, namely to the end of the local block, and to shorten those lifetimes, one has to put the expression with the compound literal in a new, smaller local block. The advantage of those long lifetimes is that lifetimes are typically long enough for it not to cause issues in C. C also does not have RAII.
Both C++ and Rust have varying lifetimes of temporaries and have RAII. Both C++ and Rust have had messes with lifetimes, C++23 changed lifetime rules for the range-initializer expression of range-based for-loops, and Rust changed lifetimes rules in Rust 2024 such that whether a specific piece of Rust code has a deadlock or not, depends on its edition, and editions are generally not specified per-file but per-project.
Temporary lifetime extension can be tricky for both developers and language designers.
But the borrow checker can make it worse in some situations, for it can push developers towards bug prone designs that have greater risks of deadlocks, just to satisfy the borrow checker. The borrow checker also mostly enabled the language designers to go wild with lifetimes, since they did not have to worry as much about UB as long as they were in the not-unsafe subset, so the issues with deadlocks might be worse in practice than if they had been more careful and restrained with lifetimes.
It can also be very subtle whether Rust code has deadlocks or not. One of these Rust programs has a deadlock, the other does not. The difference is the presence and absence of temporary lifetime extension, as per the "{}".
I guess this must be the fearless concurrency I am hearing about. /s
In general I understand why people like RAII and the idea of not worrying about pesky details such as resource cleanup is appealing, but the philosophy in C is that the compiler should not do such things behind your back and perhaps this is sometimes valuable. I like this more because things are explicit and visible and I rather want to have tools that tell me that what I do is correct rather than a language that does a lot of things implicitly behind my back (especially if this is correct 99% of times but sometimes surprisingly is not). This is why I am not a fan of C++ nor Rust. Thank you for the nice example illustrating issues in Rust arising from this.
I don't like the "fearless concurrency" motto, because it often gets discussed in isolation of all kinds of concurrency and ways to access resources in systems languages.
It suffices that the resource being accessed concurrently isn't inside in same memory space like shared memory, mapped regions, a database connection, where the Rust type system can do very little to prevent other processes, or conflicting SQL queries without proper transactions, to mess up with the data coherency.
But C++ "struct" has many more features than C "struct". Virtual functions aka compiler-generated invisible vtables, constructors (initialization functions) and destructors (automagically called deinitialization functions), the whole templates complex of features...
You can set a "contract evaluation semantic" for contracts. One of them is "observe", which only prints a message on contract violations. With "ignore", nothing at all happens.
I'm pretty sure that housing, cars and food are #1, #2 and #3. Your definition of household spending seems a little unconventional. If pets are household spending, surely so is food for humans?
Well yes, self-declared. China's economic success came after becoming less and less communist in practice. The most (in practice, as observed in real-world communism) communist thing about China is the authoritarian state with a one-party system, which to be sure is better than a full-on one person dictatorship.
Marx viewed capitalism as a necessary precondition for communism. His argument for this was, that communism cannot be built out of poverty. It requires the immense material wealth and industrial capacity that only capitalism can generate. It's probably why the historical communism was such a failure, as it was built out of poverty and not out of abundance.
In this regard, China seems to be closer to Marx' vision of a communist society.
The GDR mostly had the economic preconditions, but one problem or maybe two: its government was basically a puppet of the USSR government, and it was not brought into power by the people. Could have been interesting.
I predict that China will not achieve the communism that Marx had in mind neither. Why? Because I don't believe in predictions about radical changes in highly complex systems. You can make changes, but then you need to watch and see what actually happens instead of sticking with what some guy came up with in his room 150 years ago. Past performance of communism (so-called, but the only one that has ever existed) and current indicators (the autocrats like their power) are stronger predictors than what Marx wrote.
In a possible future if(!) and when AI can do all the work, we might need something like communism, or better extreme social democracy (democracy with massive redistribution), because the alternative is a an economic inequality that makes the Industrial Revolution times in the UK look like 70s Sweden.
Marx doesn't make a prediction here, but merely identifies the necessary precondition for communism, namely, the material abundance generated by capitalism. Fully automated luxury communism cannot emerge without this foundational framework.
However, it is a necessary condition, not a sufficient one. Post-scarcity and automation do not guarantee a transition to communism
Obviously they want you to use the web interface so they can show you ads and gather more data about you (for ads).
JMAP support turns out to be a strong signal for the business model of an e-mail provider. IMAP they have to have, JMAP is for those who actually care about supporting local client software.
reply