
C2 Programming Language - luu
http://c2lang.org/
======
blt
I'd love to see an evolved C that targets the most performance-obsessed
programmers. Features like:

* 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.

~~~
theseoafs
The main issue would be fixing the problem of pointers; high-performance code
is hard to write in C because of pointer aliasing. Rust has an interesting
approach in its ownership model but I think a performance-oriented C evolution
would require another more general solution.

~~~
aidenn0
ANSI rules for aliasing, plus the restrict keyword go a long way to address
this.

~~~
danieltillett
Yes. Pointers are only a problem if you do things with them that confuses the
compiler.

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.

~~~
arthurcolle
What are your use cases that require this kind of performance? High
performance order matching or other trading/financial applications?

~~~
danieltillett
DNA sequencing data processing [1]. It is a hard problem that needs a lot of
processing power thrown at it to solve.

1\. [https://www.nucleics.com/peaktrace/peaktrace-basecaller-
over...](https://www.nucleics.com/peaktrace/peaktrace-basecaller-
overview.html)

------
bitshiffed
As a C-enthusiast, I came in assuming that I wouldn't like this. It actually
looks very interesting though.

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).

~~~
noobermin
Have to echo the sentiment (if at least to give the authors some encouragement
if they are reading this). I saw the title and thought, "not another attempt
to supercede C..." but it sounds rather interesting so far. I love high-level
hacking as much as the next guy, but I can see how this can be easier for
C-lovers to not hate since it explicitly doesn't try to be more high level.

------
PythonicAlpha
I am not sure, if it is really worthwhile to produce a C equivalent language
in the year 2013 for more productivity.

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.

~~~
SomeCallMeTim
There is value in a C replacement, but it would need mindshare even more than
features.

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.

~~~
vvanders
I'd think that having a GC and runtime associated with it would prevent Go
from even being considered for a Systems language.

------
nadams
> For array types, C2 introduces a new operator, namely elemsof(). This
> returns the number of elements in an array

sigh

PHP - count

Python - len

C++ - .size (vector)

C - macro or stored

C# - .Length

~~~
PythonicAlpha
Yes, "elemsof" is not only another new name, but in my opinion, it is also a
name that does not disclose itself easily.

Good naming in programming is an art.

~~~
kmill
It seems to have been chosen so there is some parallelism between sizeof and
elemsof.

~~~
bitshiffed
It also makes the fact that you are referring to a size/length/count of
elements, and possibly not bytes, very explicit.

~~~
PythonicAlpha
To me it does not disclose that easily. The parallelism between "sizeof" and
"elemsof" seems to me very constructed. "size" and "elements" are not similar
words.

To be logical at all, the name should be "numelemsof" or "countelemsof" ...
but I guess, those names are already to long for C purists ...

~~~
andresmanz
That's true all too often. Meanwhile, though, I prefer long and expressive
names. You can easily find functions like _getNumberOfEnemiesOnSamePlatform()_
in my C and C++ code. I don't think it's very hard to understand what that
function does. With a few special exceptions, I haven't written any comments
for almost two years and nobody ever complained.

~~~
PythonicAlpha
Then I would not call you "C purist". The "C purists" I knew, refused to much
typing. It also was the reason they refused other languages for example such
with "tiresome long" words like "begin" and "end".

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 ...

~~~
JoeAltmaier
I've been plagued by supposed 'purists' all my career. What they are, really,
is bad at typing. They won't refactor a crap method because it would take them
too long _to type it all_

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.

~~~
PythonicAlpha
I never had a formal typing class and I guess I am still not that fast in
typing, but with the years I learnt my keyboard (even in the US and the German
variant) and for my opinion I am typing fast enough now, since I have to think
sometimes between the strokes, still.

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.

------
Sprocklem
I see a few questionable decisions in the type system:

* 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.

------
flyinglizard
From someone who mostly deals with embedded systems, I like that. All of the
modern system languages essentially rely on having a virtual memory model and
force you to use GC. Both these prerequisites essentially rule out something
like Go for a microcontroller (it can work, just not be useful beyond a
novelty).

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.

------
ori_b
I should ask the same question that people asked me when I introduce my
language:

Do you have interesting code written in it?

------
Nadya
I'm not a C programmer by any means - and the languages I've dealt with don't
have signed/unsigned. So I don't fully understand the merits and drawbacks of
them.

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.

~~~
RogerL
They removed the _default_ types. Meaning no int or unsigned int. They do have
int8, int16, int32, uint8, uint16, and so on. You are forced to be explicit.

[http://c2lang.org/site/language/basic_types/](http://c2lang.org/site/language/basic_types/)

~~~
Nadya
That's what I get for glancing (asking silly questions already answered in a
relevant section)! :) Thanks. That makes a _lot_ more sense.

------
tagrun
A few features from Go that can make things better and help preventing certain
class of bugs:

* 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

------
nwmcsween
> int32 instead of int. In C2 you always specify the size

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.

~~~
SomeCallMeTim
I've encountered this prejudice against specific-width types before. It
confused me then as now.

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"?

~~~
AnimalMuppet
Well, let's say I'm implementing something like STL's vector. I've got a size
(number of elements). What type should it be? Clearly something int-like, but
what exactly?

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.

~~~
SomeCallMeTim
If you've got generics (like templates) or macros, you make your int be
different for different vector scales.

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.]

