The C2 Programming Language
c2lang.org
c2lang.org
* fine-grained control over alignment
* automatic generation of SoA code from AoS code
* first-class SIMD types
* pragmas to switch the compiler into branch-avoiding codegen
* cache line size as a built-in constant, with ability to compile a binary that contains several versions of the complete program optimized for different cache line sizes
* user-defined calling conventions
* vectors, matrices, and quaternions (taking care of 90% of the cases where you really want operator overloading in C++)
* ability to treat an integer as an array of bits, bytes, or smaller integers, a la Terry Davis's "Holy C"
And the standard library could contain some nice performance-oriented stuff like:
* portable memory allocator that exposes pages, virtual memory indirection, reserve vs. commit, etc.
* fixed-point math
* approximate transcendental functions
* bitwise stuff a la the "Stanford Bit Twiddling Hacks"
while also adding modules and cleaning up declarations like C2 does.
I think a lot of programmers would like it.
if aliases(a, b)
slowpath
else
fastpath
;;
Considering that this language seems to also keep track of bounds on the pointers, you could probably do something similar.As someone who writes C code that needs maximum performance (my problem is cpu bound) the two biggest performance gains were moving to icc (Intel’s compiler) and writing my own thread-safe memory pool allocator to avoid malloc.
1. https://www.nucleics.com/peaktrace/peaktrace-basecaller-over...
Modules and imports look to make things much smoother, function pointers and structs are friendlier, and more explicit data types are something many C projects already adhere to.
I'm curious to see how/if the compiler handles blocks and C11 threading/atomics, with the proper libraries (blocksruntime/musl).
I think, that C has still some usages, but for bigger projects, it is IMHO not feasible to use C or an equivalent for the whole project.
Most usage I see in generated code or small code samples that have to run rather fast. My questions:
* for a faster C, is there really a new language needed? (can't we go with better compilers)
* C2 should provide better tooling, but at first it is a drawback, since old tools are not working or are limited. How does that fit together? Would it not better, to use just C for generated code (where the usability aspects are also neglect-able).
Of course, every programmer wants to create a new language, but most of them are not lasting long ... and C2 did not convince me from the front-page.
I think Go has a good combination of mindshare and features for system software development. Rust may as well, though I know less about it.
sigh
PHP - count
Python - len
C++ - .size (vector)
C - macro or stored
C# - .Length
Good naming in programming is an art.
To be logical at all, the name should be "numelemsof" or "countelemsof" ... but I guess, those names are already to long for C purists ...
I on my part (in spite using C myself) think that typing code is not that problem, but typing the right code. And -- at least when you are not alone programming -- every code line is read 10 or more times more often than it is written. So, to be clear and understandable is much more valuable to me, than come away with less strokes ...
The best investment in my career I ever made is, typing class in high school. It has separated me from the crowd at every job. Its more important that so many other irrelevant 'purist' ideals.
But when I look back at my career, I never had the feeling, to be to slow in typing even for Module II -- a language, that would never ever get the approval of the "C purists".
Doing refactoring, I use a simple trick myself -- I do much copy and paste ;) ... and delete (!) the copied stuff afterwards.
I think, as a programmer, it is a good property to be lazy -- but you should merely use it for code reuse instead for avoiding typing.
Oh, I forgot: I use vim, a typing avoidance editor. You can avoid lot of keystrokes or mouse moves with that editor. But not to avoid real content.
What do you think of the auto keyword in C++? I've personally never found typing out the types to be a problem.
But I don't think, that "auto" was specified to reduce typing. I see it more as a possibility to follow the "DRY" principle (don't repeat yourself).
There might be cases, where for example the return types of functions might change and you don't want to change every caller.
Templates are of course an other example, because the return types of templates oftentimes are depending of the input types. You of course can use those template declaration stuff, but it is very ugly and oftentimes clumsy.
I also found a nice example, where it really can help to make things more easy to read, here:
http://stackoverflow.com/questions/252671/auto-c-c/12573433#...
I think, the real usages are rare, that is also the reason, it was specified rather late.
Whenever you write a new type, just write a sizing function for it using sizeof. I like that Go is taking a similar route, except that one just implements the signature.
* Why is char equivalent to int8? If C2 is keeping 8-bit chars, why not use uint8?
* Why isn't there a primitive size type a la size_t or rust (i|u)size to increase portability?
Beyond this, when I first saw this link, I expected to be disappointed with what they'd done. I was pleasantly surprised to find I liked it.
There are a few things I'd personally want to see, like lambdas and nested functions, some more intelligent error handling, fixed point math, etc. But its a good step forward.
Do you have interesting code written in it?
However I know enough to question this:
>The default int and float types have been removed, as have type modifier like short, long, signed, unsigned.
If the goal is this:
>C2 aims to be used for problems where currently C would be used. So low-level programs, like bootloaders, kernels, drivers and system-level tooling.
It is my understanding that signed/unsigned is exactly the type of concern you have when dealing with low-level, embedded, or binary code. eg. Bit masking, bit shifting, raw memory
So I'm a bit confused. The removal of them seems a bit contrary to the domain goal of the language.
They have int8, int16, int32, int64 and uint8, uint16, uint32, uint64, and float32, float64.
They don't have short, int, unsigned int, signed short int, long, unsigned long, long long, unsigned long long int, float, double, long double, etc.
* no parentheses for if/switch/for, and mandatory {}, no semicolons
* fallthrough in switch
Also some sweet features like
* replace while with a generalized for
* struct methods
* multiple return values (this might be a stretch)
* if with variable definition (if x := y; x<z { ... } )
* not sure if it already has but type inference
Have fun porting that, this language is already dead out the gate.
It also seems to ignore low level details on how compilers optimize programs, Rust actually invested into this on the language side and wasn't just some syntastic difference from C.
I understand that C and Java have (sometimes) different use cases, still I feel reasonably confident that 32-bit arithmetic is going to be efficient enough on most platforms of interest (some embedded platforms might be a problem).
It's true that something like the Posix int_fast_16_t (etc) types might be useful though.
It seems to me that porting apps that rely on default types like int, where the int size/behavior changes between platforms, have about 1000x more chance of compatibility issues when trying to get the same code to run on new platforms. Sure there could be a performance hit on, e.g., a system that is optimized for 32 bit and you specify 16 bits. That's what types like fast_int16_t are for in C/C++. But porting the code is just easier when the types can't change out from under you.
Early versions of C couldn't even decide whether char was signed or unsigned; how is specifying uint8 or sint8 not strictly better than a char that you couldn't be sure whether it was signed or not? How is specifying uint16/32/64 or sint16/32/64 not strictly better than saying "[unsigned] int"?
If I make it an int, then on a tiny machine, it might only be 16 bits. That means that the vector can only hold 64K elements. But that's probably OK, because if I'm playing with a chip where ints are 16 bits, it probably doesn't have enough memory, address space, or need to contain more elements than that.
But if I'm on a supercomputer, int might be 64 bits, and vector might need to hold that much. That is, the size of int tends to generally scale in the same neighborhood as the other capabilities of the machine.
If I have to decide how big to make the size of a vector, what size do I pick? int64? That works for the supercomputer people, but it means that an 8051 has to do 64 bit operations to use my vector package. That's... less than ideal.
#if WE_ARE_ON_A_TINY_MACHINE
typedef uint16_t vector_size_t;
#elif WE_ARE_ON_A_SUPERCOMPUTER
typedef uint64_t vector_size_t;
#else
#error "Unsupported platform."
#end
That's better than your code which inserts 100,000 things into a vector mysteriously breaking on certain platforms (on which you may or may not have tested your code).In fact, though, I would think that an 8051 vector would need to be profoundly simpler than a supercomputer vector; not just differently sized. When you're dealing with 1-16k of RAM and not much more ROM, a full "vector package" isn't what you need, but rather a really, really limited vector package that only does exactly what you need and no more.
In fact, you probably want a version with an 8-bit "length" value -- or even a 7-bit length with some other relevant flag stored in the final top bit, for space optimization reasons.
Source: I was the lead developer on an original Game Boy game, which ran on a CPU that, IIRC, was roughly an 8053 (it had instructions somewhat related to an 8080 or Z-80, lacking all the 16-bit instructions, but adding an 8-bit fast-memory operator reminiscent of the 6502). Back in those days you didn't have "packages." You had code snippets (in assembly language, of course) that you shaved bytes off of to make them fit. And then you shaved more bytes off.
[edit: clarity, and note that it's the Game Boy I was talking about; originally said Game Boy Advance, which was an ARM CPU. Also did a game on that device, but it was the Game Boy I meant to describe.]