[HN Gopher] Checked C
       ___________________________________________________________________
        
       Checked C
        
       Author : soheilpro
       Score  : 134 points
       Date   : 2022-12-21 18:29 UTC (4 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | kelnos wrote:
       | Thinking about this at a higher level, the real problem is that
       | we use C arrays at all. But we can't stop using C arrays, because
       | libc and a huge body of other C libraries out there represent
       | lists of data using C arrays.
       | 
       | As a useful counterexample, glib has GArray, GPtrArray, and
       | GList, along with functions that you use to manipulate the lists.
       | Those functions are presumably implemented correctly, and will
       | prevent you from making out-of-bounds accesses.
       | 
       | But of course those things are not widely adopted, because
       | they're not standardized, they're not in libc, and libc has not
       | been reimagined such that all of its APIs take and return these
       | safer list primitives instead of bare C arrays.
       | 
       | (And sure, GArray etc. are not necessarily suitable everywhere,
       | as they require heap allocations. But I could imagine a safe
       | abstraction that could allow for using stack or static
       | allocations to back it.)
       | 
       | So I see something like Checked C as a band-aid, when the
       | language and stdlib just needs a complete overhaul. Obviously
       | that's incredibly unlikely to ever happen, so something like
       | Checked C is a decent compromise, I guess.
        
         | sramsay wrote:
         | > As a useful counterexample, glib has GArray, GPtrArray, and
         | GList, along with functions that you use to manipulate the
         | lists. Those functions are presumably implemented correctly,
         | and will prevent you from making out-of-bounds accesses.
         | 
         | > But of course those things are not widely adopted, because
         | they're not standardized, they're not in libc, and libc has not
         | been reimagined such that all of its APIs take and return these
         | safer list primitives instead of bare C arrays.
         | 
         | I'm really not sure why the second thing is regarded by C
         | programmers as such an insuperable barrier to the first thing.
         | 
         | I absolutely understand that there are circumstances where
         | extreme portability is a major requirement. That, and C's
         | ability to operate in highly constrained environments are among
         | its most laudable features.
         | 
         | But many of us (including me) write user-facing C applications
         | that have neither requirement and where Glib is either already
         | installed or easy to install. Why not just go ahead and use it?
         | If you're trying to get it to run on a tiny embedded system or
         | in some land without Glib . . . well, this isn't the program
         | for you!
         | 
         | I feel like this is more of a weird cultural prejudice than a
         | technical matter. People run programs in JavaScript (or
         | Haskell, or Python) with _hundreds_ of dependencies, and while
         | some find that annoying, I don 't hear people in these
         | communities objecting to _idea_ of dependencies the way people
         | do with C.
         | 
         | Could the standard library be better? Of course. But there's
         | something to be said for not including a lot of batteries in
         | the _standard_ and just using the third-party tools that are
         | available.
        
       | emmanueloga_ wrote:
       | Does anybody know how does this compare to https://compcert.org/
       | ?
        
         | ryao wrote:
         | It does not. One is a language extension that claims to prevent
         | certain classes of issues. The other is a C compiler that
         | claims to do nothing to prevent those classes of issues. The
         | two are not comparable at all.
         | 
         | You would be better off comparing it to Astree, which is a
         | static analyzer written by the group that wrote the Compcert C
         | compiler.
         | 
         | https://www.absint.com/astree/index.htm
         | 
         | Astree claims to be able to prove the absence of use-after-
         | free, which the checked C documentation says that checked C
         | does not prevent.
         | 
         | You would need to check to see if Astree can prove the absence
         | of all of the issues that checked C is intended to prevent, but
         | at a glance that seems possible. In theory, Astree can be used
         | to fix all of them by doing fixes until it stops complaining.
        
       | belter wrote:
       | "A Formal Model of Checked C" -
       | https://news.ycombinator.com/item?id=30321535 - 37 comments - 10
       | months ago
       | 
       | "Checked C" - https://news.ycombinator.com/item?id=26190403 - 133
       | comments - 2021
       | 
       | "Refactoring the FreeBSD Kernel with Checked C" -
       | https://news.ycombinator.com/item?id=25989115 - 41 comments -
       | 2021
       | 
       | "Achieving Safety Incrementally with Checked C" -
       | https://news.ycombinator.com/item?id=19424106 - 21 comments -
       | 2019
       | 
       | "Checked C: Making C Safer by Extension" -
       | https://news.ycombinator.com/item?id=17939537 - 55 comments -
       | 2018
       | 
       | "Checked C: extension to C that adds static and dynamic checking"
       | - https://news.ycombinator.com/item?id=16588483 - 92 comments -
       | 2018
       | 
       | "Checked C" - https://news.ycombinator.com/item?id=11899925 - 156
       | comments - 2016
        
         | dang wrote:
         | Thanks! Added a few:
         | 
         |  _C to Checked C by 3C_ -
         | https://news.ycombinator.com/item?id=30857289 - March 2022 (1
         | comment)
         | 
         |  _A Formal Model of Checked C_ -
         | https://news.ycombinator.com/item?id=30321535 - Feb 2022 (37
         | comments)
         | 
         |  _Why Checked C when there was Verona?_ -
         | https://news.ycombinator.com/item?id=26499846 - March 2021 (2
         | comments)
         | 
         |  _Checked C_ - https://news.ycombinator.com/item?id=26190403 -
         | Feb 2021 (133 comments)
         | 
         |  _Refactoring the FreeBSD Kernel with Checked C [pdf]_ -
         | https://news.ycombinator.com/item?id=25989115 - Feb 2021 (41
         | comments)
         | 
         |  _Refactoring the FreeBSD Kernel with Checked C [pdf]_ -
         | https://news.ycombinator.com/item?id=24019185 - Aug 2020 (13
         | comments)
         | 
         |  _Achieving Safety Incrementally with Checked C_ -
         | https://news.ycombinator.com/item?id=19424106 - March 2019 (21
         | comments)
         | 
         |  _Checked C: Making C Safer by Extension_ -
         | https://news.ycombinator.com/item?id=17939537 - Sept 2018 (55
         | comments)
         | 
         |  _Checked C: extension to C that adds static and dynamic
         | checking_ - https://news.ycombinator.com/item?id=16588483 -
         | March 2018 (92 comments)
         | 
         |  _Checked C_ - https://news.ycombinator.com/item?id=12049548 -
         | July 2016 (3 comments)
         | 
         |  _Checked C - A Safer C /C++ from Microsoft_ -
         | https://news.ycombinator.com/item?id=11936418 - June 2016 (3
         | comments)
         | 
         |  _Checked C_ - https://news.ycombinator.com/item?id=11899925 -
         | June 2016 (156 comments)
        
       | WalterBright wrote:
       | Checked C:                   int a[5] = { 0, 1, 2, 3, 4};
       | _Array_ptr<int> p : count(5) = a;  // p points to 5 elements.
       | 
       | My proposal for C:                   int a[5] = { 0, 1, 2, 3, 4};
       | int p[..] = a;  // p points to 5 elements.
       | 
       | https://www.digitalmars.com/articles/C-biggest-mistake.html
       | 
       | https://github.com/Microsoft/checkedc/wiki/New-pointer-and-a...
        
         | elcritch wrote:
         | I like your version, but how do you annotate the size from
         | existing things like "main(int *argv, argc)" to know that the
         | size is argc?
        
           | wahern wrote:
           | There was a proposal during the C23 process to make "main(int
           | argc, char *argv[argc])" work as one would expect, as well as
           | some similar changes elsewhere, such as with structure
           | members. They went through several revisions but never made
           | the cut, I think partially because they all required at least
           | some minimal backward incompatibility.
           | 
           | IMO, if GCC or clang implemented and ran with those proposed
           | changes, they'd probably be accepted for the next C revision,
           | and become popular long before then. This is mostly a matter
           | of time and motivation; corporate funded developer time seems
           | to be mostly focused on half measures; e.g. type attributes,
           | rather than fundamentally improving pointer and array
           | semantics. But if someone put in enough time and effort,
           | including going through the rigmarole of integration into
           | mainline, this could happen.
        
           | kelnos wrote:
           | You just... annotate it? Like, I don't see what the issue is.
           | You just write                   int main(int argc, char
           | **argv : count(argc)) {}
           | 
           | If you're already creating an extension for C, then it's fine
           | to "change" its signature in this way. Or am I
           | misunderstanding your objection?
           | 
           | Sure, the compiler can't verify that argv does indeed have
           | argc elements, but hopefully we can rely on the kernel and C
           | runtime to populate things properly. If not, I would say it
           | doesn't matter that the compiler can't help you here; your
           | system is screwed beyond repair already.
           | 
           | At the very least, the compiler _can_ emit bounds checking to
           | ensure that you don 't try to access past argc elements in
           | that array, which is still valuable.
           | 
           | Edit: it occurs to me that you were talking about
           | WalterBright's version, not the version in Checked C. But I
           | think my comment still applies: if you're changing how things
           | work, then you just keep changing how things work to cover
           | cases like this.
        
           | WalterBright wrote:
           | Create an adapter:                   int main(int argc, char
           | **argv) { return myMain(argv[0 .. argc]); }
           | 
           | Strings can be done like this:                   char [..] s
           | = p[0 .. strlen(p)];
        
             | elcritch wrote:
             | Hmmm, the "[..]" is a fat pointer right? Couldn't you just
             | say:                   int main(char [..] args)
             | 
             | Maybe with some way to tell the compiler the correct
             | parameter order if needed? Perhaps:                   int
             | main(char [..argc] argv)
             | 
             | I'm curious if ELF and other formats have enough info to
             | figure that mapping out?
        
               | WalterBright wrote:
               | > the "[..]" is a fat pointer right?
               | 
               | yes
               | 
               | > if ELF and other formats have enough info to figure
               | that mapping out?
               | 
               | No, as there is no semantic connection between `argc` and
               | `argv`.
        
         | tomcam wrote:
         | Elegant, but of course it would be. It's like you're a trained
         | professional or something ;)
        
           | WalterBright wrote:
           | not my first rodeo! ABEL was the first language I designed
           | (for Data I/O) back in the 80s.
           | 
           | ABEL = "Advanced Boolean Expression Language", a language for
           | programming PLDs (Programmable Logic Devices) which was a
           | core business for Data I/O.
        
           | bachmeier wrote:
           | There's no substitute for decades of having programmers
           | giving you (and shouting at you) blunt feedback on your
           | programming language proposals.
        
             | WalterBright wrote:
             | Here's the timeline:
             | 
             | 1. who would do such a dumb feature
             | 
             | 2. what, are you insane?
             | 
             | 3. it becomes obvious
             | 
             | 4. other languages adopt it
        
         | gavinray wrote:
         | You might show an example of how to use D's templates (if it's
         | possible) to emulate the more complex example of computing the
         | bounds from an input argument                 char
         | *strncpy(char * restrict dest : count(n),
         | const char * restrict src : count(n),                   size_t
         | n) : bounds(dest, (_Array_ptr<char>)dest + n);
        
           | WalterBright wrote:
           | https://news.ycombinator.com/item?id=34085835
        
             | gavinray wrote:
             | I meant something more like this (although this doesn't
             | QUITE compile, but it's close I think):
             | static ubyte* [n*2] requires_ptr_twice_as_large_as_input(n
             | : uint)         (             ubyte*[n] input,
             | ubyte*[n*2] output,         ) {             output[0..n] =
             | input[0..n];             output[n..2*n] = input[0..n];
             | return output;         }              void main()         {
             | ubyte[10] input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
             | ubyte[20] output = new ubyte[20];
             | requires_ptr_twice_as_large_as_input!(10)(&input, &output);
             | }
        
         | KingLancelot wrote:
         | Fat pointers are a good idea, but I think it'd be a better idea
         | to store the start and evd pointers instead of a pointer to the
         | first element and a size_t.
        
           | 1980phipsi wrote:
           | Why?
        
             | masklinn wrote:
             | I'd guess it's because that's what C++ does. Though it's
             | unclear to me that C++-style iteration (where you increment
             | a running pointer until you reach an EOI pointer) is much
             | used in C.
        
               | WalterBright wrote:
               | Storing two pointers into the same array is a memory
               | safety problem. It's hard to implement a borrow checker
               | when there are two live mutable pointers into the same
               | memory object.
        
         | sirwhinesalot wrote:
         | It's a shame this will never get through the insane bureaucracy
         | that is the C standards committee. Had they listened to you all
         | the way back in 2009, C11 might have been a game changer the
         | same way C++11 was. Alas.
         | 
         | At least there's BetterC ;)
        
           | WalterBright wrote:
           | This proposal could very well save C, as array bounds
           | overflows are consistently the #1 cause of corruption bugs in
           | shipped C software.
        
             | ryao wrote:
             | In theory, sound static analyzers could be another method
             | by which this is achieved in existing projects. They claim
             | to be able to catch all instances of this. Some examples of
             | sound static analyzers include:
             | 
             | https://www.absint.com/astree/index.htm
             | 
             | https://github.com/NASA-SW-VnV/ikos
             | 
             | https://github.com/static-analysis-engineering/CodeHawk-C
             | 
             | I have planned to try using them on OpenZFS for a while,
             | but I am still busy reviewing and fixing reports made by
             | conventional static analyzers. I plan to look into these
             | next.
             | 
             | That said, at least one of them claims to be able to prove
             | the absence of issues in C that checked C's documentation
             | explicitly says it cannot prevent. The obvious one is use-
             | after-free.
        
               | WalterBright wrote:
               | I don't know how a static analyzer could do this:
               | size_t i = some_function(); // gets return value from
               | environment         array[i] = 3;
        
               | roywiggins wrote:
               | If it's sound it will point out that there's a potential
               | for an error if it can't prove otherwise. To silence the
               | error you'd have to manually put a check in.
        
               | ryao wrote:
               | A sound static analyzer in theory can check the safety of
               | that by examining all code paths and complain whenever
               | any exist where it is possible to go out of bounds. It is
               | called sound because the absence of a complaint means it
               | has proven the absence of the issues it is meant to
               | catch.
        
           | jeffybefffy519 wrote:
           | It doesnt need to get through any committees to have impact.
           | Microsoft just has to use it (which i assume they are given
           | they are the authors) and then its had impact.
        
             | adastra22 wrote:
             | I don't think the comment you are replying to is talking
             | about MSFT's Checked C?
        
             | ryao wrote:
             | Do they still refuse to update their compiler to support
             | any version of C beyond C89?
             | 
             | Unless they have changed course, it seems more likely that
             | Microsoft will drop NT for a UNIX kernel than Microsoft
             | would put this into their compiler. I assume that this is
             | by Microsoft Research and work by Microsoft Research is
             | almost never used by Microsoft. The only exception I know
             | is Drawbridge, which they reportedly used in Azure.
        
               | my123 wrote:
               | SQL Server on Linux runs on Drawbridge, with NTUM and
               | all.
        
           | ryao wrote:
           | > It's a shame this will never get through the insane
           | bureaucracy that is the C standards committee. Had they
           | listened to you all the way back in 2009, C11 might have been
           | a game changer the same way C++11 was. Alas.
           | 
           | This comment did not age well:
           | 
           | https://news.ycombinator.com/item?id=34086304
           | 
           | A quick test with `clang -std=c89 -pedantic` says it was in
           | C99. Amazingly, it seems that almost nobody knew about it.
        
             | sirwhinesalot wrote:
             | Not the same thing at all, that only works with compile-
             | time known sizes.
        
               | WalterBright wrote:
               | Pascal arrays were fixed at compile time, which I quickly
               | discovered made Pascal rather useless without extensions.
        
               | ryao wrote:
               | The example was for compile-time known sizes.
        
         | Xeoncross wrote:
         | Yes, needing a fixed-sized array seems like a fairly common
         | need to me.                   a := [5]int32{0, 1, 2, 3, 4} //
         | Go              let mut array: [i32; 5] = [0, 1, 2, 3, 4]; //
         | Rust
        
           | masklinn wrote:
           | C has fixed-size arrays.
           | 
           | The problem is that it doesn't use them much, and gets rid of
           | them as soon as possible:                 int a[5] = {1, 2,
           | 3, 4, 5, 6};            printf("%d\n", a[8]);
           | 
           | in clang, this warns, by default, on both misuse sites
           | "excess elements in array initializer" and "array index is
           | past the end of the array". Which is good.
           | 
           | However things go downhill as soon as you pass the arrays
           | downstack:                   #include <stdio.h>
           | static void foo(int *a) {             printf("%d\n", a[8]);
           | }         static void bar(int a[]){
           | printf("%d\n", a[8]);         }         static void qux(int
           | a[6]){             printf("%d\n", a[8]);         }
           | int main() {             int a[5] = {1, 2, 3, 4, 5};
           | foo(a);             bar(a);             qux(a);         }
           | 
           | no warning anywhere, even under "-Wall -Weverything".
        
             | [deleted]
        
             | klodolph wrote:
             | Yeah, so the syntax is a bit funny but you can actually get
             | the bounds checking you want here:                 #include
             | <stdio.h>            static void qux(int a[static 6]){
             | printf("%d\n", a[8]);       }            int main() {
             | int a[5] = {1, 2, 3, 4, 5};         qux(a);       }
             | 
             | I get,                 test.c:9:5: warning: array argument
             | is too small; contains 5 elements, callee requires at least
             | 6 [-Warray-bounds]
             | 
             | I did not enable any warning flags at all, this is just
             | default Clang on a Mac.
             | 
             | If you want to catch the a[8] inside the function you need
             | something else.
        
               | ryao wrote:
               | It appears that Clang will warn even without this syntax
               | while GCC does not warn unless it has this syntax. At
               | least, it did when I dropped the `static 6` from the
               | example.
        
               | Jasper_ wrote:
               | Unfortunately, `int a[static 3][static 4]` does not work.
        
               | klodolph wrote:
               | That's because you'd write it as:                 int
               | a[static 3][4]
               | 
               | You only need to put static on the outermost type, the
               | one that decays into a pointer. Same thing applies if you
               | need restrict:                 int a[static restrict
               | 3][4]
               | 
               | which is ugly but gets the job done. Think of int
               | a[3][4], when used as a function parameter, as "pointer
               | to int[4]" (the 3 disappears completely), and think of
               | int a[static 3][4] as "pointer to first of at least 3
               | int[4]".
               | 
               | (Not trying to defend C here, just explaining how C
               | works.)
        
               | WalterBright wrote:
               | The explicit "6" is a problem if you aren't using fixed
               | size arrays.
        
               | klodolph wrote:
               | Yes, this was in direct response to someone talking about
               | fixed-size arrays. Think of this as just "one small way
               | in which C does not happen to be broken" rather than some
               | kind of endorsement of C!
               | 
               | Note that you could                 static void qux(int
               | n, int a[n])
               | 
               | but this changes the interface somewhat and there are
               | lots of reasons why you might want to avoid VLAs in C.
        
               | WalterBright wrote:
               | The problem with that syntax is you have to repeat it
               | every time `a` is forwarded to another function. The
               | array data and length need to be combined into a single
               | semantic entity.
        
               | klodolph wrote:
               | Yes, but I don't think a deeper discussion about the
               | flaws of array handling C is really going to illuminate
               | anything here. The conclusions generally go in one of
               | three ways--either you choose to use a different
               | language, choose to deal with C (with tools like static
               | analyzers or instrumentation), or choose to make
               | proposals to the C committee.
               | 
               | Proper array types are not present in C and they're
               | unlikely to be added at any point in the future, so if
               | the conversation is "the array data and length need to be
               | combined into a single semantic entity", then the
               | conversation is no longer about C, but the starting point
               | for choosing another language.
               | 
               | The int a[static 6] syntax made it into the language
               | because it's a small enough change that it's not
               | disruptive to existing uses of C, but it still has some
               | benefit (I've used it, I've seen its benefits).
        
               | WalterBright wrote:
               | My proposal is backwards compatible and will not disrupt
               | existing use.
        
               | klodolph wrote:
               | Do you have a write-up somewhere?
        
       | gavinray wrote:
       | Note that active development seems to be continuing here:
       | 
       | https://github.com/secure-sw-dev/checkedc-llvm-project
        
       | jimbob45 wrote:
       | Why not just use C++?
       | 
       | Also why can we not get better syntax for C? Function pointer
       | syntax is so bad that people actively avoid using them. #pragma
       | once is a hack. Every string library function is actively
       | dangerous in addition to puts/gets.
       | 
       | I know that nobody wants to be the one to mess with the core
       | language and ruin it but this is awfully low-hanging fruit that
       | hasn't been fixed in 50 years.
        
         | flohofwoe wrote:
         | The stdlib needs a modernization much more than the language,
         | unlike 'C the language', 'C the stdlib' is still stuck deep in
         | the K&R era (together with POSIX).
         | 
         | For a different language syntax it makes a lot more sense to
         | consider using a different language in the first place though,
         | because everybody has a different opinion what such a 'better
         | C' syntax should look like (e.g. it sounds like you'd actually
         | want Zig).
        
         | omeysalvi wrote:
         | >Why not just use C++?
         | 
         | Nothing good has come to anyone who started an argument with
         | those words.
        
         | gavinray wrote:
         | Am sort of curious what the difference is between this and
         | templated constexpr functions with span<T, N> in C++
        
         | mirekrusin wrote:
         | It has been fixed. The fix has the codename "zig".
        
           | pjmlp wrote:
           | It isn't a fix when it still allows for use after free.
        
           | shrimp_emoji wrote:
           | I heard it was "Rust".
        
             | anfilt wrote:
             | Rust is not exactly a C replacement. Definitely the better
             | choice these days over C++ in my opinion if you can use
             | rust.
             | 
             | It can be made to function more like C with #![no_std].
             | However that is an even less than batteries included
             | experience than C.
        
               | masklinn wrote:
               | > Rust is not exactly a C replacement.
               | 
               | Rust is absolutely a C replacement.
               | 
               | Whether C heads want to use it is a more complicated
               | question. But some are very much into it (e.g. Brian
               | Cantrill).
               | 
               | > It can be made to function more like C with #![no_std].
               | However that is an even less than batteries included
               | experience than C.
               | 
               | std assumes you have a heap and IO, which most C
               | environments do.
               | 
               | no_std removes all that (leaving only libcore as
               | baseline), however you can re-add a dependency on "alloc"
               | to get allocations and most of the standard collections
               | back (all but hashset and hashmap, because no secure
               | RNG).
               | 
               | You can also / instead fill your needs with third-party
               | crates more dedicated to restricted or freestanding
               | environments, like heapless
               | (https://crates.io/crates/heapless).
        
               | tialaramex wrote:
               | You get a lot more in core (and thus no-std) than the
               | free standing C language.
               | 
               | For example C's qsort lives in the standard library,
               | whereas in Rust although [].sort() needs alloc, the
               | [].sort_unstable() is a core feature!
               | 
               | str::split_once(['5', '7']) will split a string at the
               | first digit 5 or 7... You need considerable work to do
               | that in C, and doing it modifies the string. In Rust it's
               | a core feature.
               | 
               | Of course Rust is relying on the fact that none of the
               | machine code is emitted unless you use these features,
               | indeed split_once is fully generic, the types used only
               | come into existence because you called the function. So
               | presumably this was not practical as the fundamental
               | language for writing Unix fifty years ago.
        
               | maxbond wrote:
               | I think you & GP are using different senses of
               | replacement ("drop in replacement" vs. "replacement for
               | greenfield projects"). You might consider Rust to be the
               | latter (with qualifications, eg, excluding certain
               | architectures & proprietary programming environments) but
               | it's explicitly not the former (it's interoperable with
               | C, but not compatible with C).
               | 
               | I think we should avoid saying "replacement" in general
               | because eliminating all lines of C isn't a goal worth
               | pursuing, C doesn't need to die for Rust to succeed, and
               | there's room enough in this world for a hundred safe
               | systems languages fulfilling different niches. I think a
               | lot of people feel attacked & invalidated by the idea of
               | a "C replacement" that isn't C compatible, like we're
               | telling them their skills are no longer necessary or
               | valuable, which is untrue & leads to flamewars and
               | misunderstandings.
        
               | zozbot234 wrote:
               | Rust is absolutely a "drop-in" replacement to C in most
               | cases even for existing projects, it was absolutely built
               | with that goal in mind. You can go as fine-grained as
               | replacing a single function with a Rust-coded version
               | (even using bindgen to ingest existing C headers) -
               | though that generally involves unsafety because you're
               | dealing with general pointers, extern calls and such.
               | Even Checked C cannot prove these things 100% safe, it
               | just catches common misuse.
               | 
               | (Of course some C projects could abuse the preprocessor
               | in ways that make it infeasible to even replace a C
               | function with a Rust equivalent, but that's incredibly
               | rare. And Rust has macro facilities of its own.)
        
             | chaosite wrote:
             | Rust is more comparable to C++ than C.
        
           | seanw444 wrote:
           | Looking forward to it becoming more mature. Really cool
           | language.
        
         | constantcrying wrote:
         | >Also why can we not get better syntax for C?
         | 
         | Backwards compatability.
         | 
         | >Function pointer syntax is so bad that people actively avoid
         | using them.
         | 
         | That is because C syntax mistakenly put the return value before
         | the parameters. You use function pointers if you have to.
         | 
         | >#pragma once is a hack.
         | 
         | It is a hack to prevent the previous hack of #ifdef'ing the
         | thing.
         | 
         | >but this is awfully low-hanging fruit that hasn't been fixed
         | in 50 years.
         | 
         | It is literally impossible to fix.
        
           | jimbob45 wrote:
           | There are ways to fix backwards compatibility, no? You
           | introduce the new syntax, let it sit for several years, and
           | then deprecate the old syntax. Would it truly be that
           | difficult to introduce a "fn" keyword? Also #includeHeader
           | "myHeader.h" would solve the #pragma once problem.
           | 
           | I simply can't tell if we're not fixing this stuff out of
           | laziness, out of fear, or because no one wants to admit that
           | no one knows who's holding us back.
        
             | constantcrying wrote:
             | C++ addresses most of your concerns already. The headers
             | are C++23 iirc, somewhat similar to your proposal.
             | 
             | I don't think you really understand what C actually is. C
             | basically does not compete as a programming language. On a
             | UNIX like it is the language of the kernel and as such its
             | quirks inevitably represent the quirks of the kernel, you
             | use C if you want to talk to the kernel.
             | 
             | >Would it truly be that difficult to introduce a "fn"
             | keyword?
             | 
             | Yes, literally impossible. Just look at the controversy of
             | C23 removing the almost entirely unused K&R function
             | declaration syntax.
        
           | elcritch wrote:
           | Ugh, the C syntax makes it so hard to parse, humans or
           | machine.
           | 
           | I recently submitted a PR for the `c2nim` import tool to
           | handle double function pointers. I didn't actually understand
           | the C code until I got the transpiler working despite
           | cdecl.org:                   // posix signal
           | void(*signal(int, void (*)(int)))(int);
           | 
           | in Nim becomes:                   var signal*: proc (a1:
           | cint; a2: proc (a1: cint)): proc (a1: cint)
           | 
           | Well I'm 99.5% certain at least. Even now I'm uncertain of
           | the C syntax. And I've not been bold enough to test 3rd order
           | C function pointers. I figure that's probably C code you
           | don't wanna touch if possible.
           | 
           | https://github.com/nim-
           | lang/c2nim/blob/11f2c5363dfe7e8c7c8ce...
           | 
           | The other annoying one is that "signed" and "unsigned" are
           | basically adjectives, but "long" can be both a type and a
           | modifier. So it's difficult to parse unless you're the target
           | C compiler. Technically you can, but you have to use
           | backtracking.
        
             | secondcoming wrote:
             | That nim version isn't much better IMO, but I am unfamiliar
             | with the language.
        
               | kelnos wrote:
               | I'm completely unfamiliar with the language but was able
               | to read it from left-to-right very easily:
               | var signal*: proc (a1: cint; a2: proc (a1: cint)): proc
               | (a1: cint)
               | 
               | That reads to me as:
               | 
               | Variable signal is a pointer to a function that that
               | takes two arguments (an int, and a function that takes an
               | int), and returns a function that takes one argument (an
               | int).
               | 
               | Of course, I'm assuming my interpretation is correct...
               | perhaps it's not ;)
        
               | elcritch wrote:
               | That's right. It's actually just an ugly bit of code
               | though it's pragmatic.
               | 
               | Note that Nim uses "*" as a public symbol sigil not a
               | pointer. Its a bit odd at first coming from C but is nice
               | and consistent.
        
               | shirleyquirk wrote:
               | I agree, I prefer Nim's alternate syntax for this sort of
               | stuff:                   var signal*: (cint,(cint)->void)
               | -> (cint)->void
        
             | slavik81 wrote:
             | The signed and unsigned keywords work the same way as long,
             | e.g., `unsigned` alone is equivalent to `unsigned int`.
        
               | elcritch wrote:
               | Yah but you can't have "unsigned unsigned". You can and
               | do have "long long", or possibly a "long long long" in
               | addition to the saner "long int".
        
               | constantcrying wrote:
               | >Yah but you can't have "unsigned unsigned".
               | 
               | Seems like a good thing to be honest.
        
               | elcritch wrote:
               | Lets not give the C committee ideas ;)
               | 
               | But actually I'd suggest the opposite of disallowing
               | "long long" and making it like signed/unsiged as purely a
               | modifier.
        
             | xormapmap wrote:
             | > void( _signal(int, void (_ )(int)))(int);
             | 
             | This is trivial to parse if you use spiral rule, humans or
             | machine.
        
             | constantcrying wrote:
             | >Ugh, the C syntax makes it so hard to parse, humans or
             | machine.
             | 
             | As a _generalization_ I completely disagree. But for
             | function pointers specifically, yes, they are easily the
             | worst part of the C syntax.
             | 
             | >void( _signal(int, void (_ )(int)))(int);
             | 
             | That's just declaring signal as function (int, pointer to
             | function (int) returning void) returning pointer to
             | function (int) returning void, DUH. Thank you cdecl.org
             | 
             | But notice how absolutely ugly it is that the final return
             | type comes _first_ , that is due to the C function
             | signatures.
        
             | WalterBright wrote:
             | > difficult to parse
             | 
             | Not really. Just create a bit mask.
             | 
             | https://github.com/dlang/dmd/blob/master/compiler/src/dmd/c
             | p...
        
               | elcritch wrote:
               | Thanks! I'd read you had a full c compiler, this is
               | awesome.
               | 
               | Looks like there's only about ~388 lines of logic to the
               | bitmask? haha your definition of difficult might not
               | match mine. ;)
        
         | [deleted]
        
         | WalterBright wrote:
         | D has had a BetterC subset of D for a while:
         | 
         | https://dlang.org/spec/betterc.html
        
       | nottorp wrote:
       | Hmm. Didn't Turbo Pascal have array bounds checking 3 billion
       | years ago when we all had pet dinosaurs? It could have simply
       | been added to the compiler in C as well...
        
         | baq wrote:
         | Turbo Pascal had a lot of good ideas back in the late 80s and
         | early 90s which were ridiculed back then and are now considered
         | best practices... modules, safe strings, safe arrays, Delphi
         | added quite nice objects. Alas, it was never popular in the
         | Internet age. Just imagine if we had pascalscript instead of
         | JavaScript - a decade of wasted developer time saved...
        
       | timmg wrote:
       | Quite honestly, I love what MS has done with JavsScript with
       | Typescript. It would be great if they could do the same for C.
       | 
       | I guess the hard part will be the fact that all your dependent
       | libraries will (likely) still be unsafe.
        
         | pjmlp wrote:
         | See also https://devblogs.microsoft.com/cppblog/high-
         | confidence-lifet...
        
           | flohofwoe wrote:
           | I'm a bit confused, at the start they talk about C++, but
           | some of the code examples look like C. Do those checks also
           | work in the C compiler? (the difference is kinda important,
           | because unlike Clang, the MSVC C++ compiler doesn't have
           | enough non-standard language extensions to compile C code
           | that was written in the last 20 years).
        
             | pjmlp wrote:
             | They talk about C++, because that is what mostly matters to
             | Visual C++ customers, however /analyse mode also works in C
             | code.
             | 
             | https://learn.microsoft.com/en-us/cpp/code-quality/code-
             | anal...
        
               | sendfoods wrote:
               | I'm a bit confused. Didn't Herb Sutter essentially fork
               | clang and extended the codebase in the beginning? Is
               | microsoft working with that fork and (most importantly)
               | re-contributing?
        
         | phailhaus wrote:
         | I'm begging them to do the same for Python.
        
           | corndoge wrote:
           | They made pyright which is pretty rad
        
             | phailhaus wrote:
             | Yeah it's pretty great, but still hamstrung by the inherent
             | limitations of the language itself. Would love to see a new
             | language on top of Python that treats types as first-class
             | constructs.
        
       | pjmlp wrote:
       | Older discussions on Checked C,
       | 
       | https://news.ycombinator.com/item?id=30321535
       | 
       | https://news.ycombinator.com/item?id=19424106
        
       | guerrilla wrote:
       | Why not frama-c instead?
        
       ___________________________________________________________________
       (page generated 2022-12-21 23:00 UTC)