Herb Stutters new syntax for C++
All in all pretty interesting. The declaration syntax has a lot in common with Odin.
Herb talks about how backward compatibility with C, via cfront was key to the adoption of C++. That transition wasn't fast - it took 10 years.
It seems like a variety of languages are tacking the parameter passing issues. Val seems to be more academically thought through than the "parameter styles" here, but it's worth thinking through more about what they mean and what the trade offs are.
The named return value mechanism, is nice. It might be better than Odins in so far as it allows multiple named return values. They are passed back in a struct.
Since it's based on C++ there are some potential performance issues - for example move requires the source to still be able to run a dtor. Some of the other examples seem to add extra overhead (like the uninitalized bool check on out
).
Not having some kind of spec, or manual around the language, makes it hard to analyze what we have and why. Most of what I have here came from the CppCon 2022 talk.
as
and is
out
behavior, handling uninitialized seems like a performance hit (needs a bool)union
use std::variant
is also cost&
and *
thoughshared
and unique
(and later garbage collection)From watching the CppCon talk
Is claimed to not be a new language per se, but an experiment for future.
Introduces a new syntax
name : () -> string = {
// do something
return "some string"
}
name
introduces a new name for a thing. The section afterwards is the "type", in this case it's a function that takes no parameters and returns a string. The equal introduces the implementation. If the implementation is just an expression it's not necessary to have the braces.
Has inout
and the like.
For creating something on the heap can use
s := new<std::string>("world");
There are two "allocators" unique and shared. The default is unique, and that is what the statement above uses.
Has "Uniform Function Call Syntax" mechanism (UFCS)
Talks a fair amount how can mix with C++ - important for adoption (uses TypeScript as another example).
MITRE 2022 Most Dangerous Software Weaknesses
Use is
and as
for casting. Can get rid of most C++ cast styles. Importance around is
and as
is it allows generic code.
Unary operators are suffix. So
a : int = 10;
aPtr : _ = a&;
Hmm. Same presumably applies to !
, -
(?), +
, ~
and '*' (dereference). On looking on other examples, it does appear to be the case.
Added next
, can be used on all loop types.
Looks like type declarations are in the "read left to right" order. So I see in an example
call_my_framework: (msg: * const char) =
std::cout << msg;
This is also an example of a function with a single statement, so doesn't need {};
For a lambda, you can just leave off the name, which is nice and consistent.
Guarentees initialization before use. Safe to have uninitialized variables.
Definate first/definate last use. Initialization safety use tracking.
in
, inout
needed for initialization safety. The out thing is a bit odd in so far as it is optional if it's initialized, so presumably there is a bool somewhere indicating if it is initialized.
Nice. It has a syntax for named returned variables (like Odin).
f: () -> (i: int, s: std::string) = {
i = 10;
s = "Hello";
return;
}
// Destructuring (I think from C++) aka "structured bindings"
auto [a, b] = f();
It has the following parameter styles
in
(in is default). Are automatically const
and will do &
as neededcopy
- just takes a copyinout
- as if passed by referencemove
- implicitly moves from last use. Need to say move
at call site.forward
- auto&&
with contract.named_function : (i: int) = print(i); // named function
main: () -> int = {
vec: std::vector = ( 1, 2, 3, 4);
// Lambda
std::ranges::for_each(vec, : (i : int) = print(i); );
// Range-for body
for vec do : (i: int) = print(i);
}
On the last point with for
described as being situation where a function is called with different parameters...
How to do capture. "unnamed function capture" with $.
main: () -> int = {
s := "ish\n";
// Range-for body
// The `s$` captures s in the lambda
for vec do : (i: int) = { std::cout << i << s$; } );
}
Hmm not sure about that one. Uses it will post conditions.
Wants to get rid of reference from C++, because it only needed to exist for parameter passing, and adds lots of complexity to the language. The parameter passing styles presumably replace that.
Where do you put attributes? For example calling convention?
CppFront doesn't appear to have pointers (except in unsafe code).
What is the inout
and other "parameter styles" mechanism being discussed? There appears to be a talk about that.
The capture idea is interesting, but if I use the variable more than once, do I need to repeat used of $
? Or is it just the first.
Need more information on the "left to right" decl syntax.
Probably need to look into more around perfect forwarding.