
C-for-all: Extending C with modern safety and productivity features - albertoCaroM
https://cforall.uwaterloo.ca/
======
notacoward
I like the general idea, but the result seems just as full of garbage as C++.
Remember the first time you saw a lambda declaration in C++? That sequence of
familiar-seeming characters to mean something _totally_ different probably
threw you a bit. I know it did me. C-for-all's constructor/destructor syntax
reminds me of that.

    
    
      // bonus doc bug: "with" hasn't been introduced yet
      void ^?{}( VLA & vla ) with ( vla ) { // destructor
    

The syntax for redefining ++ or -- (which already seems spurious) is even more
opaque.

    
    
      S & ?+=?( S & op, one_t )
    

Other features, like left-to-right declaration syntax and postfix function
calls, seem to have no use except to make one programmer's code harder for
another programmer to understand. Then they throw in the rest of the kitchen
sink, with all of C++'s overloading and polymorphism and inheritance plus both
kinds and traits. The result is even more complex and even more surprising (in
a bad way) to actual C programmers than C++ or for that matter APL. If not for
the absence of templates, I'd say Cforall's complexity is a strict superset of
C++'s.

If I wanted a direct C replacement with minimal improvements, I'd try D or
Zig. If I wanted a systems programming language that had more differences but
fewer surprises, Rust or Nim. The last thing I'd want is something that's both
more baroque (rococo?) and less known than any of those.

------
lerno
It’s interesting how “evolutionary approach” is used. Compare with C2:
[http://www.c2lang.org/](http://www.c2lang.org/)

I think that in the case of C2 it’s still a language that will rely on the
same paradigms as C, whereas C-for-all is more of a “kitchen sink” style of
language that moves very far from C in how the natural code solutions are.
Just the small change adding destructors and constructors is a feature with
huge impact on how data will be managed (for better and for worse)

(Full disclosure: I have contributed to C2 in the past and I’m working on the
C3 lang which is feature and syntax-wise based on C2 but goes further:
[https://www.c3-lang.org](https://www.c3-lang.org) )

~~~
pjmlp
Also think that C2 makes more sense.

------
Quequau
This has been posted here a couple of times in the distant past but for
whatever reason I can only find one old post:

[https://news.ycombinator.com/item?id=9829133](https://news.ycombinator.com/item?id=9829133)

Anyway, it seemed like an interesting project the last time I looked at it but
Rust wound up getting all my attention.

~~~
karlding
Here's the discussion from 2018 [0], which has some responses from people
involved with the C-for-all project.

[0]
[https://news.ycombinator.com/item?id=16657385](https://news.ycombinator.com/item?id=16657385)

~~~
Quequau
Yes. That's actually the discussion I was looking for. Good find.

------
kyeb
Could someone expand on why Rust "isn't a systems language"?

~~~
smt88
I think that assertion muddles their argument.

Their key points seem to be that Rust (and other existing languages) lack
backwards compatibility and have different memory management strategies.
Lumping Rust in with GC languages is confusing.

Whether either of those things matter is another story. From using TypeScript,
I'm personally inclined to believe that a superset of a difficult language
can't solve all of the underlying problems, while a totally new language can.

~~~
fluffything
All memory allocations in Rust follow a `malloc`-like API that ends up calling
`malloc` and similar at some point.

~~~
saagarjha
With memory management, the question is often when and how to release
resources, not how to get untyped memory from the operating system.

~~~
fluffything
Sure, but in Rust, the programmer writes code that calls malloc manually,
which is completely different from Java.

------
pcr910303
I really don’t need an extended-C with productivity features... as that’s one
of the defining points of C(the language is small). Fixing the warts (like
different behavior between the overflow of unsigned ints & signed inta) would
have been fine.

I personally want a better stdlib for C; fix the defiancies of <string.h>,
removing the global locales (changing function behaviors according to LC_* was
a really, really bad idea[0]), etc...

Does anyone know of an alternative stdlib for C?

[0] [https://github.com/mpv-
player/mpv/commit/1e70e82baa9193f6f02...](https://github.com/mpv-
player/mpv/commit/1e70e82baa9193f6f027338b0fab0f5078971fbe)

~~~
kannmig
[https://www.musl-libc.org/](https://www.musl-libc.org/)

~~~
saagarjha
That doesn't fix the issues mentioned. (Whether it's an "alternative" stdlib
for C is debatable; nobody ever said that glibc is "the" stdlib for C…)

~~~
ftvy
It is the de facto standard on Linux.

~~~
pjmlp
That doesn't make it the official implementation of ISO C, just one among
many.

------
dvt
I'm sure a lot of very smart people are working on this, and I don't want to
detract from their dedication, but man this language looks like a mess. And in
no small part because it wants to be backwards compatible with C (the
reasoning is unconvincing -- _why not_ just use C++?).

In the age of Go and Rust, which already have a hard time finding niches, I
don't really think there's any room for a language like this. And on the other
hand, from a research standpoint, it's probably a lot more interesting to
build a new language from the ground up.

~~~
gambiting
I don't know, I work in the games industry and we're currently building a
small project that's probably 95% C(the only C++ we have is for one library
that has to have a C++ wrapper). It's just.....we don't need the C++ features,
the compilation times are instant(last project I worked on was a large AAA
game in C++ and compiling it from scratch was about 40-50 minutes on a single
workstation), and pretty much all libs are C anyway. I'm not going to make the
performance argument since it's mostly irrelevant nowadays, but I just don't
see us using C as anything out of ordinary.

~~~
jbverschoor
Long compile times are almost always because of bad use of header files which
include basically everything, insteda of only the used component. And this
sometimes is because of bad separation of concersn / modularization.

~~~
drainyard
I used to agree with this, but having spent a while in a very good C++ project
(by C++ standards), even if we try to always forward declare and not include
any unnecessary headers in headers, we still have a clean debug build time of
30-40 minutes. Even changing a single line in a cpp file, will still take
around 30-40 seconds at best with incremental builds. I think long compile
times are in the eye of the beholder, but often it feels like people have just
gotten used to unnecessarily long compile times because they've forgotten how
fast computers are and how fast a compiler should be for most of the work
except for maybe some of the more complex optimizations in -O3. It kills
productivity, and should really be a much larger focus than it sometimes seems
to be.

~~~
hohenheim
Well said, I could not have said it better. Just to add, the productivity
boost you get from short build times, in a long run, think of a project you
work on for years, will out perform ANY gain you get from using a library,
templates, and the like that kills your build time.

------
rwmj
Can we talk about the proposed new features:

How are tuples different from structs? You can pass around and return whole
structs (not pointers) just fine in plain C.

Underscores in int literals should probably be proposed to the ISO committee
for C itself. A similar concept works successfully in OCaml. (Binary literals
would also be useful).

I've never felt that C lacked sufficient control structures, and the new ones
proposed here just seem like they will confuse people. What specific problem
is each new control feature trying to solve?

Adding exception handling (to C) seems like an actively bad idea. What are the
semantics? How does unwinding work exactly and how would it interact with
resource allocation?

Coroutines are today successfully handled in libraries, so I'm not sure what
you gain by adding them to the language.

~~~
lerno
I wonder how they propose to solve exceptions, destructors, constructors and
overloading while being more compatible with C than D. Apparently a beta was
promised for "early 2019" according this:
[https://github.com/cforall/cforall](https://github.com/cforall/cforall) but
nothing is forthcoming.

Already announced in 2007: [http://lambda-the-
ultimate.org/node/2181](http://lambda-the-ultimate.org/node/2181)

~~~
lerno
Oh, looks like they have a partly completed compiler with a c transpiler
backend:
[https://cforall.uwaterloo.ca/trac/browser](https://cforall.uwaterloo.ca/trac/browser)

------
DyslexicAtheist
if safety is what they want without departing from C just use MISRA-C

 _> While C++, like C∀, takes an evolutionary approach to extending C, C++'s
complex and interdependent features (e.g., overloading, object oriented,
templates) mean idiomatic C++ code is difficult to use from C, and C
programmers must expend significant effort learning C++. _

the _" significant effort"_ for learning C++ pays off (financially), while
this certainly does not.

~~~
yitchelle
MISRA-C is just a set of rules. It does not stop humans making stupid mistakes
or ignoring rules, and causing safety to be violated.

It not as hard as rust where the binary is not built if a rule is violated.

~~~
kwhitefoot
Is it possible to check for compliance with MISRA-C rules programmatically?

If it is then it can be made part of the build process and the effect will be
the same: the binary will not get built if the rules are violated.

~~~
pjmlp
It is, but many developers have allergy to static analysers.

------
cain
I was excited to read about this. An upgraded C would be nice. Unfortunately,
after the homepage, this seems disastrously opposed to anything resembling a
"better" C.

The features page feels extremely painful to read. It took me at least two
minutes to even begin to make sense of the first section: "Declarations", then
an explanation of Tuple, immediately followed by:

    
    
      int i;
      double x, y;
      int f( int, int, int );
      f( 2, x, 3 + i );      // technically ambiguous: argument list or comma expression?
    

Tuple isn't mentioned again until seven or so lines after its explanation.
After reading further, I realise they aren't linked in any way, but this was
confusing at first. I thought I was missing something major about the syntax.

    
    
      [ y, i ] = [ t.2, t.0 ];    // reorder and drop tuple elements
    

I don't know what this even means. If this:

    
    
      [ i, x, y ] = *pt;      // expand tuple elements to variables
    

pulls out tuple elements into variables, and this:

    
    
      x = t.1;        // extract 2nd tuple element (zero origin)
    

accesses tuple elements: then what is "reorder and drop" and why does the
combination of the above two behaviour result in an ostensibly different third
behaviour?

It gets worse the further down the page I try to understand. Very
claustrophobic and presented as a mish-mash of syntax examples. I can't see
how this is any better than C's syntax, honestly. What C would benefit from is
a better baked-in stdlib, OR an easily available, downloadable, lib of helper
functionality that doesn't require any modifications to existing code (eg.
when I want a hashtable in an already-established project, I don't want to
modify my existing structs!)

~~~
crazypython
Take a look at D. Some of D's features (such as alias this and mixin
templates) may seem strange, but they come from decades of experience with C++
features- Walter Bright and Andrei Alexandrescu, two C++ pioneers, are among
D's foremost advocates. WB made the first end-to-end C++ compiler, and AA
wrote Modern C++ Design. GCC 9 now supports D.

------
GlitchMr
Wow, this is quite a trainwreck. I think it's possible to improve C while
keeping compatibility with C programs, but that's not how you should do it.

I think an improved C would be quite useful, but you really should be careful
with what you include it, and keep the language simple. A lot of functionality
feels like added because it could be added (WTF are nested routines). This way
lies worse C++.

In particular, I wouldn't look too much into what C++ does. Rather, I would
look into what Go, Rust and Zig do. `?{}` and `^?{}` are clearly inspired by
C++ constructors and destructors, but that's not the only way (in fact, it's a
rather bad approach if you want to keep things simple). For instance, you
could avoid having constructors and require full initialization for structures
with destructors. Hypothetically, it could look like this.

    
    
        struct Point {
            int x;
            int y;
        };
    
        struct Point new_point(int x, int y) {
            return { .x = x, .y = y };
        }
    
    

Meanwhile, C-for-all is mostly missing actually useful features. Slice types
([https://www.drdobbs.com/architecture-and-design/cs-
biggest-m...](https://www.drdobbs.com/architecture-and-design/cs-biggest-
mistake/228701625)) would be huge, but they are nowhere to be seen. Vtable
dynamic dispatch? Missing. Borrow checker? Missing. Module system (maybe a
stretch, but...)? Missing.

~~~
saagarjha
Who owns the return value of new_point?

~~~
GlitchMr
The function that calls `new_point`, the value is moved. Similarly, consider
the following case.

    
    
        struct Point a = new_point();
        struct Point a2 = a;
    

Assuming `struct Point` has a destructor, this would move `a` into `a2`, and
prevent accesses to `a` after `a2` assignment, as `a` is no longer considered
to be alive at this point. C++ has a wrong default of cloning instead of
moving, but a new language could fix that.

~~~
madmax96
Why is cloning rather than moving the wrong default?

~~~
gmueckl
It isn't. Cloning is what actually happens under the hood, if a and a2 are in
different memory locations. Making a inaccessible after the assignment is
merely a convention. With a struct that only has data members, there are no
further consequences.

If the struct contains a pointer, you need a kind of additional contract that
says how the memory that is pointed to is going to be managed, particularly
when it is going to be freed and by whom. And that is where move semantics
establish a constricting convention that is intended to make that unambiguous.

------
makapuf
Linked page explains rationale, see also the list of features :
[https://cforall.uwaterloo.ca/features/](https://cforall.uwaterloo.ca/features/)

~~~
cbsmith
So this is loading for you?

~~~
makapuf
Yes, some of the many features : Tuples, left to right declaration syntax,
references with auto dereferencing, constructors destructors, nested routines,
extended case with ranges, choose (switch with no fallthrough), overloading
and polymorphism.

~~~
kwhitefoot
Quite lot of that sounds like Turbo Pascal/Delphi.

~~~
makapuf
The even added with for structs member usage in a block.

------
musicale
For some time I have been puzzled that clang and gcc don't provide an
option/ABI (maybe -safe or -mcpu=x86-64-safe) for memory safety.

Last I checked, memory safety for C (e.g. fat pointers with bounds checking)
seems to impose a ~60% performance overhead on traditional processors (with
hardware support it could be much less.) In many (most?) cases, that overhead
is worth the improvements in reliability and security.

For certain applications (probably anything network facing) I'd probably want
to compile the whole OS, libraries, and software base with -safe.

------
sremani
What does powered by Huawei mean? Are they what Mozilla is to Rust?

~~~
microcolonel
It's a more general thing. Like elsewhere in the former British empire, the
CCP is getting their fingers in the pie, and siphoning research product back
to the weapons and surveillance industry in China.

We aren't in as dire a situation here in Canada as Australia [0] seems to be,
but there's a reason it was so difficult to serve that Huawei extradition.

[0]: [https://www.news.com.au/national/victoria/news/its-a-
police-...](https://www.news.com.au/national/victoria/news/its-a-police-
station-honouring-a-police-state-outrage-as-melbourne-cop-shop-raises-chinese-
communist-flag/news-story/7d59fc8558a59eec0693c26fb9dbf31c)

------
saagarjha
More interesting page, IMO:
[https://cforall.uwaterloo.ca/features/](https://cforall.uwaterloo.ca/features/).
Personally it has a bit more than I would be comfortable adding to C while
taking the similarity stance they are. Are there safety improvements planned
with regards to bounds checking?

------
mamcx
I dream of "better C" as something that I wish existed. Not a "alternative to
C" like Rust or ADA (that is BETTER, but not C). I think:

\- A C developer must find as low friction as possible to use it.

\- It will look alike C as much as possible.

\- Will not bring a big semantic/syntax departure

\- Not bring any novel stuff or Gc. BetterC is C as will be written by the
BEST of the developers with the BEST practiques applied, and removed (as much
as possible) the most obvious mistakes or ill-advised features.

\- BetterC must be/have a transpiler. Even if that break for a while perfect
behaviors it provide a way to cleanly upgrade things forward. Because BetterC
is well writen C, the user will be encouraged to use it with the confidence of
be in the ecosystem.

\- BetterC must be incorporated (eventually?) as a front-end in a C compiler
(like LLVM). So is like have "strict on" available.

\- This mean is better if is backed by the community as a long, step-by-step
goal of C. This also mean must be done for people that actually love/like C,
just want it to be better.

\- Must provide a set of blessed libraries like unicode strings, arrays,
numbers, dates, etc. If not in-built at least included so most that use C as
all-around lang not get out (similar in this case as Rust)

\- Must encourage rewrite of critical pieces of code, despite zero-cost of FFI
with C.

\- Fix stupid syntax issues like dangling else. This is the "easiest" part I
think.

\- Find the biggest issues of the langs/common libraries and kill them.

\- NOT ALLOW STUPID BY DEFAULT. Bring the "unsafe" keyboard here. No excuses!

\- Bring sane macros.

\- Bring AGTD, pattern matching, for ... in ..., and hopefully, fast fast
compile times.

------
mnafees
Here's a snapshot from the Wayback Machine, given the original website is down
[https://web.archive.org/web/20181206232625/https://cforall.u...](https://web.archive.org/web/20181206232625/https://cforall.uwaterloo.ca/)

------
juped
Some interesting ideas here. However, C is being improved in an evolutionary
fashion; the latest revision was C18 in 2018. I like languages like this (my
favorite is D), but the only C successor language I use is C11 (this is what
clang targets; C18 is an incremental minor update to C11 that only fixes
errata).

    
    
        x = t.1; // extract 2nd tuple element (zero origin)
    

Zero-based indexing in a programming language is not necessarily a dealbreaker
but is always a worrying sign about how hard the designer thought their design
through. (This does not apply to the design of C, which does not have zero-
based indexing; arrays are indexed by offset rather than "from zero".) These
are structs with fewer names and less ceremony involved. Why would the first
field be "field 0"?

~~~
retrac
Modern computers encode the first address of memory as a binary word of all
zeros. In an array, a pointer to the array + 0 is the first element. A pointer
to the array + 1 is the second element. C is low-level, so it makes sense to
follow the machine idiom.

------
skrebbel
Obligatory name-drop: Zig is an awesome low level programming language
targeting the same space as C and CForAll. It isn't at all compatible with C
on the source level like CForAll is, but it does make it super easy to interop
with C, because it can include .h files. That means it lets you move projects
from C to Zig file-by-file. Because Zig benefits from decades of insights
about how C could've been better, it has way fewer footguns and higher
productivity.

Obviously CForAll has a learning curve advantage over Zig, being based on C
directly, but for any readers not aware, I'd say, also check out Zig.

[https://ziglang.org/](https://ziglang.org/)

~~~
banachtarski
Zig is, however, unsuitable for interactive media or scientific computing due
to the unfortunate lack of operator overloading (which is touted as a
"feature"), rendering it less general purpose than I'd like.

Other aspects of its design look good however.

~~~
olodus
Im not super sure what specific use case you are after but are you sure you
can't do this in some ways with comptime generics? I have to be able to do
most generic-like stuff with comptime (though I sometimes have to change the
implementation a bit). I also really value how clear the lack of overloading
makes the language. This way of clearly being able to follow the control flow
is one of the things I like that they kept from C.

~~~
banachtarski
Yes I've tried zig a fair bit and the lack of operator overloading made the
use untenable. The "ability to follow control flow" is, IMO, a silly argument.
I will concede that `comptime` is a nice feature.

------
ilovecaching
I would like to see C with _just_ the borrow checker - nothing else. I assume
someone has probably already done this, and I just don't know about it.

The primary advantage of C is that, and this just parphrasing a Linus
Torvald's quote - it was developed at a time when computers weren't that
powerful and so it's very close to assembly such that a proficient C
programmer knows _exactly_ what's going on under the hood.

I can't say the same for Rust or C++ which both spit out an enormous amount of
code thanks to monomorphisation and all the other "zero cost" abstractions
they employ.

------
m712
It started out so great, but at the end I was left with the impression that
someone was just trying to shoehorn features into C with quirkier syntax than
C++. That type declaration syntax will probably haunt me in my sleep.

------
xvilka
Just use the c2rust[1] tool to "extend" C.

[1] [https://github.com/immunant/c2rust](https://github.com/immunant/c2rust)

------
meed
YAFUATMCWCIN

Yet Another Fucked Up Attempt To Make C What C Is Not

C is not “unsafe” as in “flawed”: it’s designed to fill certain gaps. Its
syntactic stability through the decades - as well as its “minimalism” (for a
lack of better word) - are among its most important features.

Personally I have been having an hard time trying to figure out why there’s
some part of the industry that desperately tries to change what C is in a way
or the other.

...but probably I’m just an old Valley fart. Apologies for the rant.

------
remix2000
I’m very surprised that no one here has mentioned the Cyclone language[0] yet.
It seems to me that it tried to address the same niche as C-for-all.

[0] [https://cyclone.thelanguage.org](https://cyclone.thelanguage.org)

~~~
saagarjha
> Cyclone is no longer supported

This might be the reason.

~~~
remix2000
Like I said, it tried to be an answer to similar problems, yet it failed. By
the logic of C-for-all creators, Cyclone falls into the “evolutionary
approach” group. Why Cyclone did not succeed in spite of “revolutionary”
languages with similar aims gaining traction is what I don’t quite understand.
I have never had any occasion to try Cyclone though, so I’m only basing my
assumptions on what other people were saying about it. Still, its design
appeals more to me than, for example, Rust, because ability to include C
headers directly is IMO the very essential thing necessary to productively
rewrite an old codebase.

------
noobermin
The one thing I like in c for all seems to be (not sure) but generally every
valid c program is a valid c-for-all program. People mentioning C2 seem to
ignore that C2 is incompatible with C. Or perhaps I'm wrong on that.

------
_pmf_
Like we extend the web with "security" ... seems like a recipe for success.

------
apta
It is concerning that a pro Chinese government entity is sponsoring this
project. They're infiltrating North American institutions, where's the
oversight?

------
Dutchie2020
HN Kiss of death

~~~
mpiedrav
HN's version of Slashdotted.

They might well use UWaterloo's CS Club infrastructure, which can withstand
enough traffic. For instance, the FOSS mirror at
[https://mirror.csclub.uwaterloo.ca](https://mirror.csclub.uwaterloo.ca)

~~~
amedvednikov
Or they should use a static website and handle any amount of traffic on a $3
VPS :)

------
deepakkhealani1
Thanks

------
quotemstr
C with modern safety and productivity features is called "C++" and has been
around for decades. I'm amazed at how much effort people will expend just to
avoid the C++ boogeyman. No, writing C++ does not automatically make your code
bloated. No, using C does not guarantee lean design.

Plain C ought to be considered a legacy language and not used for new code.
There is zero reason to prefer it over whatever style of C++ you'd like. If
you want procedural struct-based C++, you can have that, but gosh, don't write
C.

~~~
0xdead
> writing C++ does not automatically make your code bloated

Sorry, but it does.

~~~
quotemstr
No, it does not.

~~~
0xdead

      $ cat hello.c
      #include <stdio.h>
    
      int main(void)
      {
       printf("hello world\n");
       return 0;
      }
    
      $ cat hello.cpp
      #include <iostream>
    
      using namespace std;
    
      int main(void)
      {
       cout << "hello world" << endl;
       return 0;
      }
    
      $ gcc -o hello_c hello.c
      $ g++ -o hello_cpp hello.cpp
      $ ll hello_*
      -rwxr-xr-x 1 root root 5880 Dec  5 14:13 hello_c
      -rwxr-xr-x 1 root root 7424 Dec  5 14:14 hello_cpp
    

I see 1544 bytes of bloat. Hope that helps.

