C3 » Blog

Christoffer Lernö
1 month, 1 week ago
For C3 I wanted to address the problem of commenting out code using block comments.

In a good overview, Dennie Van Tassel outlined four different types of comments:

  1. Full line comments, this is exemplified by REM in BASIC: The line only contains the comment and it runs to the end of the line.
  2. End-of-Line comments, in C/C++ that would be //
  3. Block comments, '/* ... */' in C/C++
  4. Mega comments, which in C/C++ can be emulated by using // on every line or using the preprocessor with #if 0 ... #endif

We can ignore the full line comments, ... Read More →

Christoffer Lernö
5 months ago
Continuing from our previous article, let's look are some more possibilities and maybe find a solution.

An even more ambitious widening strategy

The previous idea with both a maximum and minimum promotion type didn't pan out, but what if we went much further?

We use the idea of a maxint which is a signed-only integer type that is wider than the widest ordinary type. If i128 is supported natively on the target, then the maxint is i256, if the max normal int type is long (defined as 64 bits in C3), the maxint becomes an i128.

We ... Read More →

Christoffer Lernö
5 months, 1 week ago
It is generally understood that overflowing an add or a multiplication is usually a bad thing. This seems to imply that the solution is to detect and trap (quit the program or throw an exception) on such errors. But as we will see, the answer isn't that clear cut.

Commutative and associative addition?

Typically when we work with integers, we prefer that the ordering of the operands doesn't matter. For example, if we see a + b + c we'd prefer that (a + b) + c is the same as a + (b + c).

Unfortunately, if we ... Read More →

Christoffer Lernö
5 months ago
Refactoring is an important part of programming. If you are maintaining a non-trivial code base you need to constantly remove cruft and improve on solutions otherwise the code will slowly rot.

Working with improving abstractions and code quality there is also a lure which is mostly ignored, which is over-engineering. The urge to add code that feels “magical” and just does things in an extremely elegant way. You can find examples in amazing C++ templates, or some awesomely elegant Swift code that might use some combination of operator overloading, generics and pattern matching. It might look cool, but over-engineering is ... Read More →

Christoffer Lernö
5 months ago
Previously I've been writing about various ways of handling integer overflows. The short summary is that the best you get will be some kind of trade off. I've discussed Go, Swift, Zig and Rust and looked at consequences of their particular choices.

At the time of writing, C3 has a Zig-like system with somewhat stronger left hand inference. That said, it exhibits mostly the same behaviour as Zig currently does.

In this article series I'm going to investigate a few solutions I considered for C3, but first I need to explain what triggered the investigation in the first place.

A ... Read More →

Christoffer Lernö
5 months ago
Last post about arithmetics I listed the following problems related to overflow and arithmetics:
  1. Overflow traps on unsigned integers makes the mixed signedness case very hard to get right.
  2. Overflow traps cause unexpected and hard-to-spot non commutative and associative behaviour in expressions that otherwise would have been fine.
  3. Wrapping behaviour enables buffer overflows and similar exploits.
  4. In most languages it doesn't matter if the left hand sign can contain the number, what matters are the types on the right hand side, which isn't always intuitive or desired.

Let's look at some attempts to fix these problems, starting with handling mixed ... Read More →

Christoffer Lernö
5 months, 1 week ago
The defer statement is going mainstream. Go has it's own special defer which only fires on function end, otherwise defer has consistent "execute at scope end" semantics. Swift, Zig, Jai, Nim and Odin all use defer in this manner.

The problems with implementing defer is similar to implementing destructors for stack allocated objects in C++, although the presence of virtual functions complicates things.

I couldn't find anyone describing how defer is done in other compilers so when working on a version of it for C2 I had to make it up as I went along.

For posterity's sake I ... Read More →