Features

Quick tour of C∀ features. What makes C∀ better!


Declarations

Tuple

Formalized lists of elements, denoted by [ ], with parallel semantics.

int i;
double x, y;
int f( int, int, int );
f( 2, x, 3 + i );						// technically ambiguous: argument list or comma expression?
f( [ 2, x, 3 + i ] );					// formalized (tuple) element list
[ i, x, y ] = 3.5;						// i = 3.5, x = 3.5, y = 3.5
[ x, y ] = [ y, x ];					// swap values
[ int, double, double ] t;				// tuple variable
* [ int, double, double ] pt = &t;		// tuple pointer
t = [ i + 5, x / 2.0, y * 3.1 ];		// combine expressions into tuple
[ i, x, y ] = *pt;						// expand tuple elements to variables
[i, (x, y)] = 3;						// comma expression in tuple
x = t.1;								// extract 2nd tuple element (zero origin)
[ y, i ] = [ t.2, t.0 ];				// reorder and drop tuple elements
pt->2 = 5.1;							// change 3rd tuple element

Tuple-Returning Function

Functions may return multiple values using tuples.

[ int, int ] div( int i, int j ) {		// compute quotient, remainder
	return [ i / j, i % j ];			// return 2 values
}
int g( int, int );						// 2 parameters
int main() {
	int quo, rem;
	[ quo, rem ] = div( 3, 2 );			// expand tuple elements to variables
	g( div( 5, 3 ) );					// expand tuple elements to parameters
	quo = div( 7, 2 ).0;				// extract quotient element
}

Tuple Member Access

Create a tuple by selecting multiple fields by field name/index to rearrange, drop, or duplicate fields.

[ double, float ] f( int, double ) {}
struct S { char x; int y; double z; } s;
s.[ x, y, z ] = 1;						// select by name: s.x = 1, s.y = 1, s.z = 1
s.[ y, z, x ] = [ 3, 3.2, 'x' ];		// rearrange: s.y = 3, s.z = 3.2, s.x = ’x’
f( s.[ y, z ] );						// drop: f( s.y, s.z )
f( s.[ y, y ] );						// duplicate: f( s.y, s.y )

s.[ 0, 1, 3 ] = 1;						// select by name: s.0 = 1, s.1 = 1, s.2 = 1
s.[ 1, 3, 0 ] = [ 3, 3.2, 'x' ];		// rearrange: s.1 = 3, s.3 = 3.2, s.0 = ’x’
f( s.[ 1, 3 ] );						// drop: f( s.y, s.z )
f( s.[ 1, 1 ] );						// duplicate: f( s.y, s.y )

[ int, int, long, double ] x;
void f( double, long ) {}
f( x.[ 0, 3 ] );						// select by index: f( x.0, x.3 )
x.[ 0, 1 ] = x.[ 1, 0 ];				// [ x.0, x.1 ] = [ x.1, x.0 ]
[ long, int, long ] y = x.[ 2, 0, 2 ];

struct A { double i; int j; };
struct B { int * k; short l; };
struct C { int x; A y; B z; } v;
v.[ x, y.[ i, j ], z.k ];
[ int, float, double ] f() {};
[ double, float ] x = f().[ 2, 1 ];		// f() called once

The aggregate expression to the left of the . in a member tuple expression is evaluated exactly once.

Alternative Declaration Syntax

Left-to-right declaration syntax, except bit fields.

C∀C
* int p;
[5] int a;
* [5] int pa;
[5] * int ap;
* int p1, p2;
const * const int cpc;
const * [ 5 ] const int cpac;
extern [ 5 ] int xa;
static * const int sp;
* [ int ] ( int ) fp;
* [ * [ ] int ] ( int ) gp;
[5] * [ * [ int ] (int) ] ( int ) hp;
(* int)x;
sizeof( [ 5 ] * int );
int * p;
int a[5];
int (* pa)[5];
int * ap[5];
int * p1, * p2;
const int * const cpc;
const int * const cpac[5]
extern int xa[5]
static const int * sp;
int (* fp)( int )
int (* (* gp)( int ))[ ];
int (* (* hp[5])( int ))( int );
(int *)x
sizeof( * int [5] );

References

Multi-level rebindable references, as an alternative to pointers, to reduces syntactic noise.

int x = 1, y = 2, z = 3;
int * p1 = &x, ** p2 = &p1,  *** p3 = &p2,	// pointers to x
	& r1 = x,  && r2 = r1,   &&& r3 = r2;	// references to x
int * p4 = &z, & r4 = z;

*p1 = 3; **p2 = 3; ***p3 = 3;				// change x
 r1 =  3;	r2 = 3;		r3 = 3;				// change x: implicit dereference *r1, **r2, ***r3
**p3 = &y;	*p3 = &p4;						// change p1, p2
// cancel implicit deferences (&*)**r3, (&(&*)*)*r3, &(&*)r4
&r3 = &y; &&r3 = &&r4;						// change r1, r2

A reference is a handle to an object, like a pointer, but is automatically dereferenced the specified number of levels. Referencing (address-of &) a reference variable cancels one of the implicit dereferences, until there are no more implicit references, after which normal expression behaviour applies.

Constructor / Destructor

Implicit initialization and de-initialization (like C++). A constructor/destructor name is denoted by '?{}' / '^?{}', where '?' denotes the operand and '{' '}' denote the initialization parameters.

struct VLA { int size, * data; };		// variable length array of integers
void ?{}( VLA & vla ) with ( vla ) {	// default constructor
	size = 10;  data = alloc( size );
}
void ^?{}( VLA & vla ) with ( vla ) {	// destructor
	free( data );
}
void ?{}( VLA & vla, int size, char fill = '\0' ) { // initialization
	vla.[ size, data ] = [ size, alloc( size, fill ) ];
}
void ?{}( VLA & vla, VLA other ) {		// copy, shallow
	vla = other;
}
{
	VLA  x,		y = { 20, 0x01 },	z = y;	// z points to y
	//   x{};	y{ 20, 0x01 };		z{ z, y };
	^x{};								// deallocate x
	x{};								// reallocate x
	z{ 5, 0xff };						// reallocate z, not pointing to y
	^y{};								// deallocate y
	y{ x };								// reallocate y, points to x
	x{};								// reallocate x, not pointing to y
}	//  ^z{};  ^y{};  ^x{};

Nested Routines

Nested routines and call-site inferencing provide a localized form of inheritance.

forall( otype T | { int ?<?( T, T ); } ) void qsort( const T * arr, size_t size ) { /* use C qsort */ }
int main() {
	int ?<?( double x, double y ) { return x > y; } // locally override behaviour
	qsort( vals, 10 );					// descending sort
}

The local version of ?<? performs ?>? overriding the built-in ?<? so it is passed to qsort.

Qualifier Distribution

To reduce duplication, forall and storage-class qualifiers may be distributed over a group of functions/types,

forall( otype T ) {						// distribution block, add forall qualifier to declarations
	struct stack { stack_node(T) * head; };	// generic type
	inline {							// nested distribution block, add forall/inline to declarations
		void push( stack(T) & s, T value ) ...
		// generic operations
	}
}

Literals

Underscore Separator

Numeric literals allow underscores.

2_147_483_648;							// decimal constant
56_ul;									// decimal unsigned long constant
0_377;									// octal constant
0x_ff_ff;								// hexadecimal constant
0x_ef3d_aa5c;							// hexadecimal constant
3.141_592_654;							// floating point constant
10_e_+1_00;								// floating point constant
0x_ff_ff_p_3;							// hexadecimal floating point
0x_1.ffff_ffff_p_128_l;					// hexadecimal floating point long constant
L_"\x_ff_ee";							// wide character constant

Integral Suffixes

New integral suffixes hh (half of half of int) for char, h (half of int) for short, and z for size_t. New length suffixes for 8, 16, 32, 64, and 128 bit integers.

20_hh			// signed char
21_hhu			// unsigned char
22_h			// signed short int
23_uh			// unsigned short int
24z				// size_t
20_L8			// int8_t
21_ul8			// uint8_t
22_l16			// int16_t
23_ul16			// uint16_t
24_l32			// int32_t
25_ul32			// uint32_t
26_l64			// int64_t
27_l64u			// uint64_t
26_L128			// int128
27_L128u		// unsigned int128

0 / 1

Literals 0 and 1 are special in C: conditional ⇒ expr != 0 and ++/-- operators require 1.

struct S { int i, j; };
void ?{}( S * s, zero_t ) with( s ) { i = j = 0; }	// zero_t, no parameter name required
void ?{}( S * s, one_t ) with( s ) { i = j = 1; }	// one_t, no parameter name required
int ?!=?( S * op1, S * op2 ) { return op1->i != op2->i || op1->j != op2->j; }
S ?+?( S op1, S op2 ) { return ?{}( op1->i + op2->i, op1->j + op2->j; }

S s0 = { 0, 1 }, s1 = { 3, 4 };			// implicit call: ?{}( s0, zero_t ), ?{}( s1, one_t )
if ( s0 )								// rewrite: s != 0 ⇒ S temp = { 0 }; ?!=?( s, temp )
		s0 = s0 + 1;					// rewrite: S temp = { 1 }; ?+?( s0, temp );

Postfix Function/Call

Alternative call syntax (postfix: literal argument before routine name) to convert basic literals into user literals, where ?` denotes a postfix-function name and ` denotes a postfix-function call..

postfix functionconstant argument callvariable argument callpostfix routine pointer
int ?`h( int s );
int ?`h( double s );
int ?`m( char c );
int ?`m( const char * s );
int ?`t( int a, int b, int c );
0`h;
3.5`h;
'1'`m;
"123" "456"`m;
[1,2,3]`t;
int i = 7;
i`h;
(i + 3)`h;
(i + 3.5)`h;

int (* ?`p)( int i );
?`p = ?`h;
3`p;
i`p;
(i + 3)`p;

Postfix Call Examples


Overloading

Variables, routines, operators, and literals 0/1 may be overloaded.

Variable

Variable names within a block may be overloaded depending on type.

short int MAX = 32767;
int MAX = 2147483647;
double MAX = 1.79769313486231570814527423731704357e+308L;
short int s = MAX;   // select MAX based on left-hand type
int i = MAX;
double d = MAX;

Routine

Routine names within a block may be overloaded depending on the number and type of parameters and returns.

// selection based on type and number of parameters
void f( void );							// (1)
void f( char );							// (2)
void f( int, double );					// (3)
f();									// select (1)
f( 'a' );								// select (2)
f( 3, 5.2 );							// select (3)
// selection based on type and number of returns
char f( int );								// (1)
double f( int );							// (2)
[int, double] f( int );						// (3)
char c = f( 3 );							// select (1)
double d = f( 4 );							// select (2)
[int, double] t = f( 5 );					// select (3)

Operator

Operator names within a block may be overloaded depending on the number and type of parameters and returns. An operator name is denoted with '?' for the operand and the standard C operator-symbol. Operators '&&', '||', and '?:' cannot be overloaded because the short-circuit semantics cannot be preserved..

int ++?( int op );						// unary prefix increment
int ?++( int op );						// unary postfix increment
int ?+?( int op1, int op2 );			// binary plus
int ?<=?( int op1, int op2 );			// binary less than
int ?=?( int * op1, int op2 );			// binary assignment
int ?+=?( int * op1, int op2 );			// binary plus-assignment

struct S { int i, j; };
S ?+?( S op1, S op2 ) {					// add two structures
	return (S){ op1.i + op2.i, op1.j + op2.j };
}
S s1 = { 1, 2 }, s2 = { 2, 3 }, s3;
s3 = s1 + s2;							// compute sum: s3 == { 2, 5 }

Extending Types

Existing C library-types can be augmented; object-oriented languages require inheritance. C++ can only partially extend C types as constructors, destructors, conversions and operators =, [], (), -> may only appear in a class.

#include <time.h>
void ?{}( timespec & t ) {}
void ?{}( timespec & t, time_t sec ) { t.tv_sec = sec; t.tv_nsec = 0; }
void ?{}( timespec & t, time_t sec, time_t nsec ) { t.tv_sec = sec; t.tv_nsec = nsec; }
void ?{}( timespec & t, zero_t ) { t.tv_sec = 0; t.tv_nsec = 0; }
timespec ?+?( timespec & lhs, timespec rhs ) {
	return (timespec)@{ lhs.tv_sec + rhs.tv_sec, lhs.tv_nsec + rhs.tv_nsec }; // @ ⇒ C-style initialization
}
_Bool ?==?( timespec lhs, timespec rhs ) {
	return lhs.tv_sec == rhs.tv_sec && lhs.tv_nsec == rhs.tv_nsec;
}
timespec ?=?( timespec & t, zero_t ) { return t{ 0 }; }

timespec tv0, tv1 = 0, tv2 = { 3 }, tv3 = { 5, 100000 };
tv0 = tv1;
tv1 = tv2 + tv3;
if ( tv2 == tv3 ) ...
tv3 = tv2 = 0;

Overloading Examples


Parametric Polymorphism

Routines and aggregate type may have multiple type parameters each with constraints.

Trait

Named collection of constraints.

trait sumable( otype T ) {
	void ?{}( T &, zero_t );			// constructor from 0 literal
	T ?+?( T, T );						// assortment of additions
	T ?+=?( T &, T );
	T ++?( T & );
	T ?++( T & );
};

Polymorphic Routine

Routines may have multiple type parameters each with constraints.

forall( otype T | sumable( T ) )		// polymorphic, use trait
T sum( T a[ ], size_t size ) {
	T total = 0;						// instantiate T from 0 by calling its constructor
	for ( i; size ) total += a[i];		// select appropriate +
	return total;
}
int sa[ 5 ];
int i = sum( sa, 5 );					// use int 0 and +=

Polymorphic Type

Aggregate types may have multiple type parameters each with constraints.

forall( otype T | sumable( T ) ) {		// forall distribution
	struct TwoArrays {					// polymorphic (generic) type
		T * x, * y;						// two C arrays
	};
	void ?{}( TwoArrays( T ) & ta, int size ) with ( ta ) { // constructor
		x = alloc( size ); y = alloc( size );
	}
	void ^?{}( TwoArrays( T ) & ta ) with ( ta ) { // destructor
		free( x ); free( y );
	}
}
int main() {
    TwoArrays( int ) tai = { 5 };
    TwoArrays( double ) tad = { 5 };
    for ( i; 5 ) { tai.x[i] = i; tad.y[i] = i; }
    sout | sum( tai.x, 5 ) | sum( tad.y, 5 );
}

Coroutines / Concurrency

Coroutines, monitors, and threads provides advanced control-flow, similar to μC++.

Coroutine

Stackfull semi and full coroutines allow retaining data and execution state between calls.

#include <fstream.hfa>
#include <coroutine.hfa>

coroutine RunTotal {					// input numbers and return running total
	int input, total;					// communication
};
void ?{}( RunTotal & rntl ) { rntl.total = 0; }
void update( RunTotal & rntl, int input ) with( rntl ) { // helper
	total += input;						// remember between activations
	suspend();							// inactivate on stack
}
void main( RunTotal & rntl ) with( rntl ) {
	for () {
		update( rntl, input );
	}
}
int add( RunTotal & rntl, int input ) {
	rntl.input = input;					// pass input to coroutine
	resume( rntl );
	return rntl.total;					// return total from coroutine
}
int main() {
	RunTotal rntl;
	for ( i; 10 ) {
		sout | i | add( rntl, i );
	}
}

Coroutine Examples

Monitor

A monitor type defines data protected with mutual exclusion, and the mutex qualifier acquires mutual exclusion. Bulk acquisition of multiple monitors is supported.

#include <thread.hfa>
monitor Bank {							// shared resource
	int money;
};
// acquire mutual exclusion of bank on entry
void deposit( Bank & mutex bank, int deposit ) {
	bank.money += deposit;
}
// acquire mutual exclusion of both banks on entry
void transfer( Bank & mutex mybank, Bank & mutex yourbank, int me2you ) {
	deposit( mybank, -me2you );
	deposit( yourbank, me2you );
}

Monitor Examples

Thread

A thread type, T, instance creates a user-level thread, which starts running in routine void main( T & ), and joins on deallocation.

#include <fstream.hfa>
#include <thread.hfa>
thread T {
	int id;
};
void ?{}( T & t ) { t.id = 0; }
void ?{}( T & t, int id ) { t.id = id; }
void main( T & t ) with( t ) {			// thread starts here
	sout | id;
}
int main() {
	enum { NumThreads = 5 };
	T t[ NumThreads ];					// create/start threads
	T * tp[ NumThreads ];
	for ( i; NumThreads ) {
		tp[i] = new( i + 1 );			// create/start threads
	}
	for ( i; NumThreads ) {
		delete( tp[i] );				// wait for thread to terminate
	}
}										// wait for threads to terminate

Thread Examples


Control Structures

if / while Conditional

Extend if / while conditional with declarations, similar to for conditional. (Does not make sense for do-while.)

if ( int x = f() ) ...					// x != 0, x local to if/else statement (like C++)
if ( int x = f(), y = g() ) ...			// x != 0 && y != 0, x and y local to if/else statement
if ( int x = f(), y = g(); x < y ) ...	// x < y, x and y local to if/else statement
if ( struct S { int i; } x = { f() }; x.i < 4 ) ... // x.i < 4, S and x local to if/else statement

while ( int x = f() ) ...				// x != 0, x local to while statement (like C++)
while ( int x = f(), y = g() ) ...		// x != 0 && y != 0, x and y local to while statement
while ( int x = f(), y = g(); x < y ) ... // x and y local to while statement
while ( struct S { int i; } x = { f() }; x.i < 4 ) ... // x.i < 4, S and x local to while statement

Loop Control

Extend for / while / do-while iteration control.

while () { sout | "empty"; break; }			sout | nl;
do { sout | "empty"; break; } while ();		sout | nl;
for () { sout | "empty"; break; }			sout | nl | nl;

for ( 0 ) { sout | "A"; }					sout | "zero" | nl;
for ( 1 ) { sout | "A"; }					sout | nl;
for ( 10 ) { sout | "A"; }					sout | nl;
for ( 1 ~= 10 ~ 2 ) { sout | "B"; }			sout | nl;
for ( 10 -~= 1 ~ 2 ) { sout | "C"; }		sout | nl;
for ( 0.5 ~ 5.5 ) { sout | "D"; }			sout | nl;
for ( 5.5 -~ 0.5 ) { sout | "E"; }			sout | nl | nl;

for ( i; 10 ) { sout | i; }					sout | nl;
for ( i; 1 ~= 10 ~ 2 ) { sout | i; }		sout | nl;
for ( i; 10 -~= 1 ~ 2 ) { sout | i; }		sout | nl;
for ( i; 0.5 ~ 5.5 ) { sout | i; }			sout | nl;
for ( i; 5.5 -~ 0.5 ) { sout | i; }			sout | nl;
for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }	sout | nl;
for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; }	sout | nl | nl | nl;

enum { N = 10 };
for ( N ) { sout | "N"; }					sout | nl;
for ( i; N ) { sout | i; }					sout | nl;
for ( i; N -~ 0 ) { sout | i; }				sout | nl | nl;

const int start = 3, comp = 10, inc = 2;
for ( i; start ~ comp ~ inc + 1 ) { sout | i; } sout | nl;
empty
empty
empty

zero
A
A A A A A A A A A A
B B B B B
C C C C C
D D D D D
E E E E E

0 1 2 3 4 5 6 7 8 9
1 3 5 7 9
10 8 6 4 2
0.5 1.5 2.5 3.5 4.5
5.5 4.5 3.5 2.5 1.5
2 4 6 8 10
10 8 6 4 2


N N N N N N N N N N
0 1 2 3 4 5 6 7 8 9
10 9 8 7 6 5 4 3 2 1


3 6 9

Empty conditional implies 1. ~ is up-to exclusive range [M,N); ~= is up-to inclusive range [M,N]. -~ is down-to exclusive range [N,M); -~= is down-to inclusive range [N,M]. 0 is the implicit start value; 1 is the implicit increment value. Up-to range uses += for increment; down-to uses -= for decrement. The loop index is polymorphic in the type of the start value or comparison value when start is implicitly 0.

Loop Control Examples

case Clause

Extend case clause with list and subrange.

switch ( i ) {
  case 1, 3, 5: ...						// list
  case 6 ~ 9: ...						// subrange: 6, 7, 8, 9
  case 12 ~ 17, 21 ~ 26, 32 ~ 35: ...	// list of subranges
}

switch Statement

Extend switch statement declarations and remove anomalies.

switch ( x ) {
	int i = 0;							// allow declarations only at start, local to switch body
  case 0:
	...
	int j = 0;							// disallow, unsafe initialization
  case 1:
	{
			int k = 0;					// allow at lower nesting levels
			...
		case 2:							// disallow, case in nested statements (no Duff's device)
	}
  ...
}

choose Statement

Alternative switch statement with default break from a case clause.

choose ( i ) {
  case 1, 2, 3:
	...
	// implicit end of choose (switch break)
  case 5:
	...
	fallthrough;						// explicit fall through
  case 7:
	...
	break								// explicit end of choose (redundant)
  default:
	j = 3;
}

Non-terminating and Labelled fallthrough

Allow fall through to be non-terminating in case clause or have target label providing common code.

non-terminatorlabelled
choose ( ... ) {
  case 3:
	if ( ... ) {
		... fallthru; // goto case 4
	} else {
		...
	}
	// implicit break
  case 4:




choose ( ... ) {
  case 3:
	... fallthrough common;
  case 4:
	... fallthrough common;

  common: // below fallthrough
		  // at case-clause level
	...	// common code for cases 3/4
	// implicit break
  case 4:


choose ( ... ) {
  case 3:
	choose ( ... ) {
	  case 4:
		for ( ... ) {
			// multi-level transfer
			... fallthru common;
		}
		...
	}
	...
  common: // below fallthrough
		  // at case-clause level

The target label must be below the fallthrough and may not be nested in a control structure, and the target label must be at the same or higher level as the containing case clause and located at the same level as a case clause; the target label may be case default, but only associated with the current switch/choose statement.

Labelled continue / break

Extend break/continue with a target label to support static multi-level exit (like Java).

LC: {
	... declarations ...
	LS: switch ( ... ) {
		case 3:
			LIF: if ( ... ) {
				LF: for ( ... ) {
					LW: while ( ... ) {
						... break LC; ...		// terminate compound
						... break LS; ...		// terminate switch
						... break LIF; ...		// terminate if
						... continue LF; ...	// continue loop
						... break LF; ...		// terminate loop
						... continue LW; ...	// continue loop
						... break LW; ...		// terminate loop
					} // while
				} // for
			} else {
				... break LIF; ...				// terminate if
			} // if
	} // switch
} // compound

Exception Handling

Exception handling provides dynamic name look-up and non-local transfer of control.

exception_t E {};						// exception type
void f(...) {
	... throw E{}; ...					// termination
	... throwResume E{}; ...			// resumption
}
try {
	f(...);
} catch( E e ; boolean-predicate ) {	// termination handler
	// recover and continue
} catchResume( E e ; boolean-predicate ) {	// resumption handler
	// repair and return
} finally {
	// always executed
}

with Clause/Statement

Open an aggregate scope making its members directly accessible (like Pascal, but open in parallel).

struct S { int i; int j; double m; } s;	// member i has same type in structure types S and T
struct T { int i; int k; int m; } t;
with ( s, t ) {							// open structure variables s and t in parallel
	j + k;								// unambiguous, s.j + t.k
	m = 5.0;							// unambiguous, s.m = 5.0
	m = 1;								// unambiguous, t.m = 1
	int a = m;							// unambiguous, a = t.m
	double b = m;						// unambiguous, b = s.m
	int c = s.i + t.i;					// unambiguous, qualification
	(double)m;							// unambiguous, cast s.m
}

C∀'s ability to overload variables means members with the same name but different types are automatically disambiguated, eliminating most qualification when opening multiple aggregates. Qualification or a cast is used to disambiguate.

waitfor Statement

Dynamic selection of calls to mutex type.

void main() {
	waitfor( r1, c ) ...;
	waitfor( r1, c ) ...; or waitfor( r2, c ) ...;
	waitfor( r2, c ) { ... } or timeout( 1 ) ...;
	waitfor( r3, c1, c2 ) ...; or else ...;
	when( a > b ) waitfor( r4, c ) ...; or when ( c > d ) timeout( 2 ) ...; when ( c > 5 ) or else ...;
	when( a > b ) waitfor( r5, c1, c2 ) ...; or waitfor( r6, c1 ) ...; or else ...;
	when( a > b ) waitfor( r7, c ) ...; or waitfor( r8, c ) ...; or timeout( 2 ) ...;
	when( a > b ) waitfor( r8, c ) ...; or waitfor( r9, c1, c2 ) ...; or when ( c > d ) timeout( 1 ) ...; or else ...;
}

Libraries

Stream I/O

Polymorphic stream I/O via sin (input) and sout (output) (like C++ cin/cout) with implicit separation and newline (like Python).

#include <fstream.hfa>					// C∀ stream I/O
char c;  int i;  double d;
sin | c | i | d;						// input format depends on variable type: x  27  2.3
sout | c | i | d;						// output format depends on constant/variable type
x 27 2.3								// implicit separation between values:

GMP

Interface to GMP multi-precise library through type Int, e.g., compute first 40 factorials with complete accuracy.

C∀C
#include <gmp.hfa>
int main( void ) {
	sout | "Factorial Numbers";
	Int fact = 1;				// multi-precise integer
	sout | 0 | fact;
	for ( i; 1 ~= 40 ) {
			fact *= i;
			sout | i | fact;
	}
}
#include <gmp.h>
int main( void ) {
	gmp_printf( "Factorial Numbers\n" );
	mpz_t fact;  mpz_init_set_ui( fact, 1 );
	gmp_printf( "%d %Zd\n", 0, fact );
	for ( unsigned int i = 1; i <= 40; i += 1 ) {
		mpz_mul_ui( fact, fact, i );
		gmp_printf( "%d %Zd\n", i, fact );
	}
}

Miscellaneous

Backquote Identifiers

Keywords as identifier to deal with new keyword clashes in legacy code.

int `int`, `forall`;					// keywords as identifiers
`forall` = `int` = 5;
`int` += 7;

Exponentiation Operator

New binary exponentiation operator x\y (backslash) for integral and floating-point types.

2 \ 8u;									// integral result (shifting), 256
-4 \ 3u;								// integral result (multiplication), -64
4 \ -3;									// floating-point result (multiplication), 0.015625
-4 \ -3;								// floating-point result (multiplication), -0.015625
4.0 \ 2.1;								// floating-point result (logarithm), 18.3791736799526
(1.0f+2.0fi) \ (3.0f+2.0fi);			// complex floating-point result (logarithm), 0.264715-1.1922i
Multiplication is O(log y).

Remove Definition Keyword

Keywords struct and enum are not required in a definition (like C++).

struct S { ... };
enum E { ... };
S s;									// "struct" before S unnecessary
E e;									// "enum" before E unnecessary

char Types

char, signed char, and unsigned char are distinct types and may be overloaded.

#include <fstream.hfa>
int main() {
	char c = 'a';
	signed char sc = 'a';
	unsigned char uc = 'a';
	sout | c | sc | uc;					// prints a97 97
}

int128 Type

New basic overloadable type for 128-bit integers.

int main() {
	int128 wi = 1;
	unsigned int128 uwi = 2;
	wi += uwi;
}

basetypeof Type

Pseudo routine like typeof returning the base type of a type or variable.

basetypeof( const unsigned int ) usi;	// unsigned int
volatile const signed char ch;
basetypeof( ch ) sc;					// signed char
enum { N = 3 };
basetypeof( N ) si;						// signed int