
C2 Programming Language: An Evolution of C - mabynogy
http://c2lang.org/
======
earenndil
Looking at the language, I fail to see a point. It seems to fix things that
are slightly nagging, but not real problems with c (lack of real modules,
structs, default arguments, integer sizes) while failing to fix the real
problems (strings, buffer checks, metaprogramming, type introspection
(_Generic doesn't _really_ solve this, and neither does __typeof__(). A
slightly enhanced __typeof__() plus a slightly enhanced _Generic might have a
shot)).

No more includes/header files seems to imply no more preprocessor, which is a
shame because while it may have been hackish, it was one of c's greatest
strengths.

> more logical keywords (public/local replaces static)

My friends, have you heard of the wonderous c preprocessor?

    
    
        #define func
        #define local static
        #define public
    

Agree with what comex said about compilation/building.

For a slightly nicer alternative to c, what about zig[1]?

1: [http://ziglang.org/](http://ziglang.org/)

~~~
adamnemecek
Why does no more headers imply no preprocessor.

~~~
earenndil
Because #include is a major part of the preprocessor. Because I didn't see any
other preprocessor use in the example programs.

~~~
frou_dh
Maybe they meant that you do not need "permission" from a language to use a
preprocessor, and so can use one anyway.

------
comex
From a cursory look at the documentation this interests me, but with one huge
caveat: does this support incremental compilation?

The documentation goes on at some length about how the C2 compiler parses and
analyzes all source files at once, before generating code. Supposedly this
improves compilation speed because:

 _The code generation (and optimization) steps require a lot of time. So if
you have 100 C source files and the 99th file has a syntax error, the compiler
has to go through a lot of work before showing the diagnostic. In C2 it only
takes very little time. So during development, developers never have to wait
for diagnostic messages._

Except that during development of C programs, in practice, most changes will
only require recompiling one or two files. The rest of the files have already
been compiled and don’t have to be examined at all until the link step, which
is relatively fast.

Admittedly, C is simple enough, and the header file and process-per-source-
file models inefficient enough, that the C2 compiler might be able to parse
and typecheck 100 files in an amount of time similar to what make and clang
take to build two. I haven’t tested it, but let’s assume so. Then if I have an
error, I indeed wouldn’t have to “wait for diagnostic messages” (for too long,
anyway). And it would be nice that the same speed could be achieved regardless
of what I change, whereas in C touching a common header file may well require
rebuilding everything. Then again, this fundamentally doesn’t scale well.

But what if I don’t have an error? With an incremental C build, I don’t have
to wait to run and test my code, either. If the C2 compiler doesn’t support
incremental compilation, it’ll have to redo code generation for everything,
using the same backend (LLVM) as my C compiler. Thus, the ‘feature’ of
compiling everything at once becomes an antifeature.

It is possible to implement incremental compilation in a compiler more
‘natively’ than C’s file-based approach, and this can turn module-at-once
compilation from a mixed bag for performance to a pure win. If the C2 compiler
has done so, I shouldn’t be complaining! But since it’s not mentioned in the
documentation pages I looked at, I’m guessing it hasn’t.

------
GordianNaught
If any of you who found this interesting also know Prolog, I am working on a
compiled language you should check out (The compiler is written in Prolog).

[https://github.com/GordianNaught/Juicy](https://github.com/GordianNaught/Juicy)

------
audunw
With the large number of new languages coming out (and maturing) these days,
I've always found it annoying that there's not been a real attempt at a better
C. So this is nice to see.

I don't count Rust, because one of the good things about C is that it's quite
easy to write a compiler for. A better C shouldn't require a too clever
compiler.

Another attempt I stumbled across recently is Zig:
[http://ziglang.org](http://ziglang.org)

~~~
geezerjay
> I don't count Rust, because one of the good things about C is that it's
> quite easy to write a compiler for. A better C shouldn't require a too
> clever compiler.

Why is that relevant?

~~~
solidsnack9000
Maybe one reason is portability? Although the Rust strategy of leveraging LLVM
is a good answer, there are situations -- a partial implementation for the
sake of analysis, or a clean room implementation for reasons of IP or national
security -- where a simple language retains an edge.

~~~
earenndil
There _was_ a new implementation of rust in c++
[https://github.com/thepowersgang/mrustc](https://github.com/thepowersgang/mrustc)

~~~
solidsnack9000
Yeah but it still needs original rustc for verification (borrow checking).

------
tagrun
Packaging needs to be improved, especially given that it requires their fork
of llvm and clang.

deb/rpm files or at least a PKGBUILD would help make it a lot more accessible.

------
blt
looks solid, but seems to lack a few features I would want in a modern C
replacement: if-expressions, tagged unions, immutability by default.

~~~
gravypod
Why is imutability by default important to you? Why not just add const to your
definition?

~~~
taktoa
Why make it easy to use something bad and hard to use something good? The
concept of "this variable is mutable" makes more sense than "this variable is
constant" anyway; saying that a variable is mutable is like _adding features_
to it (i.e.: the ability to mutate it).

~~~
gravypod
The very name "variable" implies changing value. When you define something
that doesn't change you are defining a "constant".

I also don't think a mutable variable is bad or hard to use. Is this bad/hard
to use?

    
    
        for (int i = 0; i < 10; i++)
    

Or is this bad....

    
    
        int line_number = 0;
        char *line;
        while (read_line_from(stdin, &line))
        {
            // TODO handle line
            line_number += 1;
        }
    

I don't think so. I think much of this buzz about how bad variables are comes
from Rust merely existing and no practical examples.

What inherently makes this

    
    
        for (mut int i = 0; i < 10; i++)
    

better than our last example for loop?

If you're actually against mutability where it doesn't need to be you can
create tooling that can warn you of where you can add const. I think that's
much better.

~~~
catnaroek
> The very name "variable" implies changing value.

Variables, both in ordinary mathematics and in the semantics of programming
languages, are given meaning by substitution, not mutation. This is true even
in the semantics of imperative languages[0][1].

[0]
[https://en.wikipedia.org/wiki/Hoare_logic](https://en.wikipedia.org/wiki/Hoare_logic)

[1]
[https://en.wikipedia.org/wiki/Predicate_transformer_semantic...](https://en.wikipedia.org/wiki/Predicate_transformer_semantics)

------
enriquto
yet no closures

(arguably, the only thing easy to do in assembler that you cannot comfortably
write in C)

------
convolvatron
this really looks like a point on the interpolation between C and Go. not that
thats a bad thing.

but assuming that I think they should just have pulled in the type syntax from
Go

------
billconan
How is struct function different from c++ class member function?

------
eps
Interesting. Deserves far more upvotes.

