Hacker News new | ask | show | jobs
by aerovistae 2340 days ago
Seen this posted here years ago. Now as then, my gut feeling is that anyone doing serious work in C would never use something like this-- I feel like the fine grained low level control is exactly the reason they chose C in the first place, and they're not looking to escape from it or they would just choose a different language.
5 comments

"Why does this exist? I made Cello as a fun experiment to see what C looks like hacked to its limits. As well as being a powerful library and toolkit, it should be interesting to those who want to explore what is possible in C."

"Can it be used in Production? It might be better to try Cello out on a hobby project first. Cello does aim to be production ready, but because it is a hack it has its fair share of oddities"

It sounds like they don't intend for it to be anything other than an interesting case study.

I found their FAQ to be refreshingly honest. This is in no way suited for large projects or where multiple people will be contributing. A case study sounds like a good description.

And the authors seem quite okay with that.

Not only that, but last I looked into this library's code there was a lot of undefined behavior and general sloppiness that goes against good C practices, eg. ignoring errors, casting all types to void * literally all the time or treating char VLAs as structs without regard for alignment.

My sympathy and respect to the author, but they did not appear learn C well before trying to "fix" it. It is kind of irresponsible, I think, to say it "aims to be production ready" and write it up as something other C neophytes may be interested in with some of these issues.

> Not only that, but last I looked into this library's code there was a lot of undefined behavior

Neither GCC's nor Clang's sanitisers pick up any undefined behaviour - and it's been like that for at least the last few years I've looked at it.

As to ignoring errors, and ignoring alignment, I don't think I've ever seen anything like that in the project. I have seen several pull requests delayed so that they will.

Overall, for what it's doing, this is one of the cleaner codebases I've dealt with.

    #define alloc_stack(T) ((struct T*)header_init( \
      (char[sizeof(struct Header) + sizeof(struct T)]){0}, T, AllocStack))
You can't take char[sizeof(foo)] on the stack and cast it to a foo*. malloc implementations for example are cafeul to align the buffer they give you. Windows, for example, aligns on 8 bytes. Probably popular alloca implementations do this too. For example, googling for "alloca alignment" finds some documentation: "... returns a void pointer to the allocated space, which is guaranteed to be suitably aligned for storage of any type of object". I have seen things break in the real world when these expectations are violated. The cello tree does this in a more few places since I last looked, eg. skimming it again I see the same pattern in the Windows stack trace code. It will probably work there but it's a coincidence, and not guaranteed by the standard AFAIK.

It looks like they got rid of some undefined things I saw when I looked in 2015. eg. they used to think you can do arithmetic on void pointers, which I think even gcc -Wall would flag for you. [Edit: Trying it out it seems I am wrong, on gcc and clang you need -pedantic to get that warning.]

I'm really surprised that you both came up with opposing results... What tests were done indicating undefined behavior?
The fine-grained control is just a statement away. When you're not using the $<ident>(...) macros, it's just normal C.

It's pretty much exactly the same like the low-level-C techniques being instantly available for you in C++ or Objective C.

The biggest advantage for me in using C is that the syntax never changes.

When I go look at a C code, I don't have to look up some annotation or new syntax that got introduced behind some abstraction that gets compiled in automatically after the library is pulled from the internet by whatever build system the project uses.

> I feel like the fine grained low level control is exactly the reason they chose C in the first place

That's not the only reason, there is also simplicity, static typing and performance. If you favor the later two for whatever reason it can be used in places where you'd normal write a python/shell script or small program without too much extra effort (see https://github.com/RhysU/c99sh or suckless tools). Complexity is where Cello seems to fall down though, it seems like it introduces much more complexity than just using plain C with a decent "standard" library like glib.

> That's not the only reason, there is also simplicity, static typing and performance.

I think the only meaningful benefit here is performance.

Simplicity is at best determined by the nature of the problem and at worst a completely subjective opinion for C.

Similarly, static typing is not usually something the programmer should care about that much. You need to know which paradigm your language uses, of course, but beyond that it does not matter all that much. IMX, you're more concerned with type safety, and C is not fully type safe like, say, Java is.

Yes it's somewhat subjective, but other languages for the use case usually contain a lot more abstractions. They're more complex languages but they might enable less complex solutions to the problem at hand.

> IMX, you're more concerned with type safety, and C is not fully type safe like, say, Java is.

I'm concerned with finding errors, preferably at compile time. There have been very few times being fully type safe runtime like the jvm have done much for me compared to the java compiler. If I wanted more down that road then rust or ada would probably be better.

Measure the complexity of a language as the number of axioms required to define it. In reality, the C standard is incredibly brief, defining the core language in ~150 pages. This makes C simpler than languages like C++ and Java and the definition is not at all subjective and is useful.
You could also just pick something like Nim (https://nim-lang.org) if you wanted to hit the intersection of low effort, script-style programming with the addition of types and performance.
Did Nim compile times improve? I wrote a production project in it which was about 50k loc and I spent most time waiting for compilation.
I just checked out and built the Nim compiler + stdlib itself.

real: 161.26s (including the GCC bootstrap stage).

cloc reports 253500 lines of Nim in the project.

This was on a Ryzen 7 3700x @ 3.6GHz.

Re-running it immediately after (does not build the GCC bootstrap stage)

real 22.55s