90 comments

[ 2.6 ms ] story [ 103 ms ] thread
Consider using Go instead, as a replacement for C.
What about Rust?
Too complicated. Rust is more similar to C++ than it is to C.
What's wrong with that? Rust seems to be fully capable of doing low level things like drivers and kernels, so why would you choose less abstraction and safety instead of more?
In a time where C++ exists, C still gets used. C interop is even easier in C++ than Rust IIRC, so given the choice, C++ would get the nod much earlier I'd imagine.

That said, people use C because it forgoes abstractions and complications. Neither C++ nor Rust provide that experience. I think Go comes the closest, while being a bit nicer to work with overall.

C++ is way more complicated than Rust though.
C++ has more features than Rust but you can limit yourself pretty severely and use "simple" features to get far more safety and convenience than C without having to wrap your mind around Rust.
True for your new project from scratch when you already sucked up C++ such that you know what&when.

But at this point you know C++ pretty well (including all what you don't want to use, take a look at the CPP Core Guidelines), and using Rust is almost trivial, since Rust doesn't really introduce anything really new you wouldn't be already familiar with.

At least that was my experience.

Due to UNIX clones, and religious cargo cult on some embedded circles.
I’d say zig is closest C replacement.
I agree, and much easier than Rust to get going and then some. Other than playing with Nannou in Rust to 'get' the language, and the Rust book, I started a toy game in Zig without more than the skeleton put together here:

https://github.com/michal-z/zig-gamedev

I like Raylib, and there are bindings for most popular languages, but I like the minimalism I can start with fairly quickly in Zig. I tried Bevy for Rust, but it is a lot more involved, and Rust, so Zig it is for now.

For safety, and high-integrity software, I am sticking with SPARK2014. Rust will get there soon, but Ada/SPARK2014 have such a lead, maturity, and industry take up that I am putting Rust down for another year or more.

I kinda wish SPARK were mainstream. Ada kind of aims for the same things as Rust, but it's been around such a long time. It's amazing how long C has stayed around.
That's a bit debatable. Vlang is right there too. This would all be relative to what people are trying to do. Many people might really be looking for a C and C++ replacement, of which there are a number of viable alternatives (including good old Object Pascal), but then preferences and other factors makes things cloudy.
Rust is the one Torvalds seems most interested in, and I suspect that's a deciding factor.

Zig might be the most direct upgrade from C, but it seems like rust can mostly replace the entire concept of portable assembly, since it has zero cost abstractions.

The question is whether they should be foregoing those abstractions and complications.

C is not a language known for high security or reliability, nor is it known for being fast or easy to develop in, so by my guess based on vague anecdotal evidence, it seems that defaulting to the highest level of abstraction unless forced to do otherwise by some specific requirement is a better plan.

C and direct C replacements advertise simplicity, but if the simplicity doesn't buy you any reliability in practice, why bother with it?

> That said, people use C because it forgoes abstractions and complications. Neither C++ nor Rust provide that experience.

There's almost no C code you could write in an effort to "forego abstractions and complications" that isn't also C++.

I tried multiple times to grok rust, but it's still too difficult for me to understand and be comfortable. In contrary go other than the struggle of unused variable compile error, I can use it within hours.
Maybe. But it's still closer to C than go is.
Isn't there a danger that go will be cancelled?
Not at all, as long as Rob Pike is alive, I believe.
Rob Pike is 66 and the average male life expectancy in America is 76 years. Of course I wish him to live happily for many more years, but it would be presumptuous to expect him to work on Go for the rest of his life.

But although google has killed 264 projects so far [1], I believe that Go has too many dependents at Google and in industry to cancel. And even if it should happen anyway, the community will fork it.

[1] https://killedbygoogle.com/

Life expectancy of a 66 year old is 83.
Must be at least 10y more if you don’t use Java.
I stand corrected. I also forgot to consider that Rob Pike is Canadian, which further improves his statistical chances.
Yeah... Exactly. Look at all the stuff Bell Labs came out with in the 60s and 70s that still survives today, without their involvement. Go will live on regardless.
I think Go has gained enough fans that it'll survive somehow, in some form, for a long time.
How can a programming language be cancelled?
Stop providing security patches, for example.
I thought golang was open source. What am I missing?
You can't literally kill a FOSS project like you can with proprietary, but it can go away if nobody else wants to maintain it.

FOSS projects die all the time. You might want to write a patch here and there, but do you want to do all the DevOps, pay for hosting, manage testing, etc?

Maintaining a project kinda sucks.

Sure, but there are enough huge companies using Go (including organisations like banks for whom a couple of developer salaries are small change) that I’m sure someone would step up to maintain it.
By accusing it of discrimination against generic classes.
Yet discriminating unions are all fine and nobody speaks up.
Did you ever hear the tragedy of Perl the wise?
Go is a high level language, it doesn’t share any quality with C, other than perhaps bad expressiveness.
"C Is Not a Low-level Language Your computer is not a fast PDP-11."

https://queue.acm.org/detail.cfm?id=3212479

That article completely misses the point - assembly (or machine code) might not be how the "metal" works on a modern desktop(-like) CPU, but that is irrelevant when that is the lowest level that said CPUs are exposing. On such CPUs C is at the lower levels possible.

But also C isn't just for Intel, x86 and (some) ARM CPUs, there are other targets it has.

Nothing of that is exclusive to C, please provide an example of a CPU where C is the only compiler toolchain available, and exposes CPU capabilities without using language extensions.

Any example with language extensions to ISO C, allows me to provide a counter example with language extensions.

Any example where only a subset of ISO C is allowed, allows me to provide a counter example with a language subset.

Are you replying to the correct comment? I never claimed anything that would be exclusive to C. What i wrote applies equally to something like, e.g., most Pascal dialects that are around the same "level" as C.
This leaves room for such interpretation "On such CPUs C is at the lower levels possible.".

Sorry if I misunderstood it.

For some cases that's fine, but go has terrible FFI, which make it unsuitable for some use cases, and being garbage collected makes it unsuitable for others.
Previously, previously, previously, previously, previously, ...

https://news.ycombinator.com/item?id=6047576

https://news.ycombinator.com/item?id=14091630

https://news.ycombinator.com/item?id=8799070

https://news.ycombinator.com/item?id=22102533

https://news.ycombinator.com/item?id=10526159

https://news.ycombinator.com/item?id=19665596

https://news.ycombinator.com/item?id=11912427

This shows up periodically and it looks pretty nightmarish (~15 years reading and writing C). If you want this kind of abstraction, I think you're better served by any of the dynamically-typed scripting languages.

One of the advantages of a language is that you can get someone with experience in that language and they'll be able to understand it (with some work for code style and libraries used etc).

This seems to be different enough you may as well just use another language.

If you want this kind of abstraction while retaining some of the upsides of C, you’re better served with Nim or similar in my opinion
It is definitely worth pointing out that this isn’t new, the idea itself is truely fascinating and the author clearly articulates this is code as art. It is definitely eye opening once you read into the details.

I stumbled across this when a new chapter of crafting interpreters came out, and I ended up doing a deep dive into how to speed up CPython. My conclusion was that it wouldn’t be possible without rearchitecture of the fundamental types, and hence unpalatable, but a fun exercise none the lesser

If you’d be wrong to so quick to dismiss Cello. Cello is an order of magnitude quicker than python, even cython can only achieve 3x on CPython without annotation. The ideas behind Cello put it somewhere around JavaScript speed, but far more extendable, and definitely worthy of further investigation.

To expand further, fat pointers (void type, void data) could be superior to NaN boxing, and I’m not aware of any interpreted languages that have seriously implemented fat pointers, but it seems to be going well for Rust.

> any interpreted languages that have seriously implemented fat pointers

Have a look at PicoLisp. It has less than a handful of data types but i uses "Tag Bits". Julia is not really interpreted but it uses pointer tags for union types to save on boxing?

Micropython uses pointer tags for small ints, maybe other things?
everybody in performant interpreters uses tagged pointers. micropython got it from lua, which got it from lisps
How does this perform on larger embedded systems where you have a fair amount of memory but no Rust toolchain with good support?

Could it possibly be useful there?

I suspect just using a tiny Lua/JS/Python would be better but maybe in some super niche case this could have a use. Probably not though.

Nim compiles to C and therefore should be able to run on anything which has a C compiler available.

To my knowledge it's been demonstrated on AVR, ARM Cortex-M and ESP32.

It's macro system comes in handy for embedded, too, as you can precompute so much stuff at compile time.

Oh yeah, I forgot about that awesome Nim feature. Kinda surprised Nim isn't 10x bigger than Zig and Go
Why comparing Zig with Nim, though?

I think Nim has quite nice standard library and production-ready. Zig, on the other side, is still highly experimental.

(comment deleted)
Are you seriously proposing banning posts about an experimental programming language because you think it is harmful? This radicalization is one of the most concerning issues with today’s society.
"Experimental programming language" is a huge stretch for this thing.

I think you need to understand a bit of some C subcultures to get this reaction. C more than other communities is about best practices to achieve certain goals like portability, stability, security, maintainability, etc. These best practices are often restrictive, or advocate cautious use of language features. Cello breaks a lot of these rules, sometimes haphazardly, and no experienced C person would advocate for some of those hacks.

But what ends up in the HN comment thread is a largely unfamiliar-with-C-culture looks at the README and comes away with the impression that this is an accessible way to learn C, which it is not.

They can advocate as much as they want, but there is nothing to understand - censorship is not justified in this context.
I'm explaining why people would say this is a poor, even irresponsible introduction to the topic. "Nothing to understand", "censorship" are extreme reactions. It's a good idea to understand criticism before dismissing it.

To take an extreme example... If a medical textbook had some strange and nonstandard information, and doctors said it should not be published because it advocates poor health outcomes... Is that "censorship"?

(comment deleted)
I'm suprised that there are so many comments advising to not use it, when even FAQ of this library basically says that it's not production ready. It always was just cool project to show off how someone can hack C to it's limits.
I’m going to use it “in production” just to spite them!
Don’t let The Man hold you back!
People keep saying not to use this, and I think that's pretty wrong-headed.

Sure, if you're going to do greenfield software development, and you don't absolutely need to kind of closeness to the metal (not just performance, but direct access) that C offers, then use something else (Rust, Zig, Go ... if you need to compile to native binaries, Java, C# & their myriad of variants if you don't).

But if you have to use C, to extend an existing project, use a specific library, or hook some other system... why not use Cello?

For sure, this is not a tight black-box abstraction, so you should strive to understand the semantics of how it works. Once you do though, it'll make your life a whole lot simpler.

If you have to use C to extend an existing system, or hook into one, or leverage C code and so on, I found Nim to be brilliant. Because it is C once compiled.

I’m using it right now at work to build our firmware for our custom embedded board. It’s been brilliant: ESP-IDF is all C (mostly, some C++ but it all has C interfaces too) and wrapping, extending, calling and integrating into those has been a breeze.

Nim wrapped around a good library can feel liberating. I feel like using it and FFIs is too uncommon.
I always get a bit sad when a nice library I come across in the wild is C++, as FFI to C++ is so much more... fiddly, in all languages, compared to a C library. The latter is a breeze.

In fact, today, I needed to be able to call the `esp_pthreads.h` functions (which describe some ESP32-specific extensions to it's pthread layer) and it took me, no joke, 5 minutes to wrap.

Pass the header through c2nim, add `{.importc, header: "esp_pthreads.h".}` pragmas to the proc definition, and done. Now I can call them without issue. Its liberating for sure!

That said, you can even wrap C++ if need be, though it's less elegant at times.

It's a great concept, but languages like Rust (https://www.rust-lang.org/), Zig (https://ziglang.org), Vlang (https://vlang.io/), etc... are already running with a similar idea to being easy to interact with C and are viable alternatives to it as well. Vlang even created its own OS, Vinix (https://github.com/vlang/vinix), to show its capabilities in this regard.

Seems to me, Cello would be more for those C programmers that didn't want to try the various alternative languages that are now out, and happen to agree with its developer's interpretation of preferred higher level abstractions and what they should look like. The point of these alternative languages is to offer features that C doesn't have or to implement them in easier or clearer ways.

This is a good point, and definitely worth considering. I would however weigh the benefits of these languages with the cost of complexifying the toolchain, adding another language into the mix, & future maintainability (I'm pretty sure I can still run `make` on the C codebase in 10 years. I'm not so sure about these others.)
I wish there was some dialect of C, with a complexity between C and C++, with simple things such as string, vector, dict...

I like V, nim, Zig, etc, but I just want a language that use the same idioms of C, with the same syntax flavor, without all the complexities of C++ (templates, inheritance, etc). I don't want complex, new features that new languages offer.

So just use C++ without those features...
That's what I do, but it doesn't change the fact that compiling C++ is pretty heavy and slow, and C++ still suffers from a lot of backward compatibility.
Sounds like you just want a library like GLib.

Vlang is the most simple in your list – it is a different syntax, but not much more complex than C.

Being an over-engineered monstrosity that it is, Glib is probably the exact opposite of what GP wants.
"Those who don't understand Glib are destined to reimplement it and have their work also referred to as an over-engineered monstrosity"
Looks interesting, but it seems to be missing something that would allow you to deal with arbitrary binary data that has nulls in it. Looking at the types[1], there's a String, but it's mapped to null-terminated C strings. And I don't see a mapping to char or a pointer to some allocated memory.

[1] https://libcello.org/learn

I like some of the ideas here, but I think it goes too far. What I want is a modern replacement for libc, that has less global state, always treats arrays as a pointer and length instead of null terminated pointers (maybe with a macro to define a struct of pointer and length), has consistent error handling, standardizes on utf-8 for strings, either handles locale in a sane way, or doesn't worry about locale and leaves it up to the application/other libraries, instead if having a broken locale system, is designed with working in a multithreded environment in mind, etc.

But, I think all the macro magic in libcelli is a bit much.

I mean, it's still an interesting project, and it's cool that it's pushing the limits of c. But a more conservative replacement for libc would be more likely to see widespread use
Yet another macro manipulating C extension hobbyist project.

The article shows it with syntax highlighting, that I could only guess wouldn’t actually work.

Awesome project, why not evolve c like this project in 2022?