Live data from Hacker News

Contracts for C

gustedt.wordpress.com

61–70 of 114 posts

Re: Contracts for C

#61

There's a bit of an impedence mismatch with Contracts in C because C++ contracts exist partially to rectify the fact that is broken in C++. Let's say you have a header lib.h: inline int foo(int i) { assert(i > 0); //... } In C, this function is unspecified behavior that will probably work if the compiler is remotely sane. In C++, including this in two C++ translation units that set the NDEBUG flag differently creates…

I think the main point of pre- and post-conditions is, that the compiler can see them and prove that they match and will never be triggered. There probably will be a compiler flag for outputting all non-proved pre/postconditions, there is already -fanalyzer. I think these conditions should be part of the type signature, different to what was suggested in the otherwise good talk you cited.

> the compiler can see them and prove that they match and will never be triggered

This is a huge challenge for a C-like language with pervasive global state. Might be more feasible for something like Rust, but still very difficult.

Re: Contracts for C

#62
post #34
post #2

I like Eiffel. But if I want to use Eiffel, I’ll use Eiffel (or Sather). I’d rather C remained C. Maybe that’s just me?

Languages are software products like everything else in computing, either they evolve or they whither and die. C especially was designed with lots of security defects, and had it not been for UNIX being available for free, it would probably never taken off.

More likely they evolve AND they whither and die. The number of software I have stopped using due to bad updates is much higher than those with not enough updates.

Re: Contracts for C

#63

Earlier quoted context omitted.

I think the main point of pre- and post-conditions is, that the compiler can see them and prove that they match and will never be triggered. There probably will be a compiler flag for outputting all non-proved pre/postconditions, there is already -fanalyzer. I think these conditions should be part of the type signature, different to what was suggested in the otherwise good talk you cited.

> the compiler can see them and prove that they match and will never be triggered This is a huge challenge for a C-like language with pervasive global state. Might be more feasible for something like Rust, but still very difficult.

You only need to check between caller and callee. If their constraints always match, it can't be triggered, if they contradict always, it will be triggered, else it can't be decided and the programmer can add annotations if he cares about, or the compiler can check what it would be like if the caller is inlined into his calling functions if that is trivial enough.

Re: Contracts for C

#64
post #58

One of the biggest problems I find with contracts whenever contracts are mentioned is that nobody seems to have a really clear definition of what exactly a contract 'is' or 'should be' (with the exception of languages where contracts are a formal part of the language, that is). I find the general concept incredibly useful, and apply it in the more general sense to my own code, but there's always a bit of "what do I a…

No wonder it looks less than awesome to you. A contract is just a hack. Ideally, it should not exist because the type system already covers the programmer's intent. Languages that have shitty types which cannot express very much must work around the problem with contracts.

Aren't contracts a feature of the type system? They encode a specific type that differs from the base type by a more complex predicate, like a constraint check in SQL.

Re: Contracts for C

#65
post #40

Earlier quoted context omitted.

The complexity of C# and C++ should be a warning, not something to strive towards. C++ has 3 reasonable implementations, C has hundreds, for all sorts of platforms, where you don't get anything else. Most C developers don't want a modern C, they want a reliable C. WG14 should be pushing for clarifications on UB, the memory and threading model, documenting where implementations differ, and what parts of the language c…

Most single C implementations have died out. There is hardly any C compiler worth using that isn't equally a C++ compiler . In fact, there is any C compiler left worth using that hasn't been rewriten into C++.

That may be true in your bubble, but I don't think this is true in general. There are still a lot C compilers out there, compared to 3 or 4 that do C++.

Re: Contracts for C

#66

Earlier quoted context omitted.

In C, sure. C is a dangerous language of its time. But these contracts don't make things better. Now you're removing control from the user. So now if an allocation fails, you crash. No way to recover from it. No getting an error signal back (NULL) so that you can say "OK, I need to clear up some memory and then try again". (Note that I'm not saying that inline error signaling such as NULL is good design - it's not).…

I'm not convinced. If something is going to cause a crash, like a nullptr, I'd rather crash near where the error happened with a nice error message, than hitting some UB crash god knows where. Do I want my app to crash at all? No, of course not. If it's crashing, there's a serious bug. At least now I know where to look for it. Should we pass back up an error signal instead of crashing? Yes, if it all possible, do tha…

The other hope for contracts is static whole program analysis can prove your program - at least in part. If you can prove some contract false that tells you where a bug is long before anyone triggers it.

Re: Contracts for C

#67
post #58

One of the biggest problems I find with contracts whenever contracts are mentioned is that nobody seems to have a really clear definition of what exactly a contract 'is' or 'should be' (with the exception of languages where contracts are a formal part of the language, that is). I find the general concept incredibly useful, and apply it in the more general sense to my own code, but there's always a bit of "what do I a…

No wonder it looks less than awesome to you. A contract is just a hack. Ideally, it should not exist because the type system already covers the programmer's intent. Languages that have shitty types which cannot express very much must work around the problem with contracts.

Partially agree, but only for a very narrow definition of what is a contract, which again is the problem stated above.

A good contract system may in fact rely on type-safety as part of its implementation, but types do not necessarily cover all aspects of contracts (unless you're referring to the full gamut of theoretical generalisations of things like dependent types, substructural types, constraint logic programming, etc), and are also not necessarily limited to things that only apply at compile-time.

Re: Contracts for C

#68
post #56

Earlier quoted context omitted.

C, not C++. Also span had no bounds checking until the introduction of .at() in C++26, which was a very silly thing to do so late in an age where the white house was asking people to use memory safe languages.

> Also span had no bounds checking While there was no reason not to have .at(), lack of bound checks by default isn't a bad thing, as inlined bound checks have the potential to highly pessimize code (esp. in loops); also standard library hardening is a thing. IMO there's much more value to be had in migrating C code (and pre-C++11 code, too) to C++ (or Rust, depending on one's tastes); RAII - that is to say, the abil…

I like how it's handled in Herb's cpp2/cppfront. If the type implements certain methods (like size()), and you turn on bounds checking, then the indexing operations (which are unsafe) are wrapped in i .

This way the indexing operation itself doesn't need to have bounds checks and it's easier for the compiler to optimize out the checks or for an "unchecked" section to be requested by the programmer.

Re: Contracts for C

#69
post #40

Earlier quoted context omitted.

The complexity of C# and C++ should be a warning, not something to strive towards. C++ has 3 reasonable implementations, C has hundreds, for all sorts of platforms, where you don't get anything else. Most C developers don't want a modern C, they want a reliable C. WG14 should be pushing for clarifications on UB, the memory and threading model, documenting where implementations differ, and what parts of the language c…

Most single C implementations have died out. There is hardly any C compiler worth using that isn't equally a C++ compiler . In fact, there is any C compiler left worth using that hasn't been rewriten into C++.

There seems to be at least 2 lcc forks (lcc-win32/win64, and pelles-c) that have their own small communities. Although maybe they are dead.

Re: Contracts for C

#70
post #13

Earlier quoted context omitted.

Exactly, panicking is a safer way to handle the situation rather than memory access violations

Safer in what sense? We have no idea whether this hypothetical code is in a userspace application that can exit safely at any time or a hard real time system where panicking could destroy hardware. A lot of important programs (like the Linux kernel) don't operate strictly on the exact letter of the standard's UB semantics. They do things like add compiler flags to specify certain behaviors, or assume implementation d…

I will never understand how C developers can catastrophize over Rust panics, a language that has a panicless "_try" version of every panic causing function that returns a Result instead, while simultaneously accepting the infinite growth of ever harder to avoid UB in C/C++ and telling people to never have undefined behavior in their code.

If you think dealing with undefined behavior is easy and you assume that people have verified that their software triggers no undefined behavior at runtime is fair game, then you should grant that assumption in favor of Rust developers having done the same with their panics, because avoiding panics is child's play in comparison to avoiding UB.

I don't know what it is about panics that triggers some mania in people. UB does not interrupt the program and therefore allows memory corrupt and complete takeover of a program and the entire system as a consequence. C developers are like "this is fine", while sitting in a house that is burning down.

There used to be a pretty blatant hibernation bug with AMD GPUs on Linux that essentially crashes your desktop session upon turning your computer on from hibernation. I've also had a wifi driver segfault on login that forcibly logged you out so you couldn't login like 9 years ago. C doesn't magically fix these problems by not having an explicit concept of panics. You still need to write software that is correct and doesn't crash before you push an update.

There is no meaningful difference between a correctness bug and a panic triggering condition with the exception that the panic forces you to acknowledge the error during development, meaning it is more likely that the correctness bug gets caught in the first place.

Post reply on HN