Future:
clib
support built in, including removing clib dependency via muslsentinel terminated pointers
. Includes specifying the sentinel._
though)trace
naked
noreturn
)value
errdefer
for handling error scenariosasync
~
would be shorter/simpler (for example).@UpperCamel
name indicates type or a comptime function that returns a type@
seems like a reasonable short hand for at
tribute, but that's not how it's used hereorelse
) seems worse than using lower snake.()
for generic parameters
_0
, _1
?+|
struct
s are implictly named (all structs are anonymous).enum
and presumably union
.*
to access the contents of a pointer.while
can specify a continue
expression. While can have else
.comptype
the non taken branch is ignored
comptime
and runtimeinterface
mechanism
Has defer
, and errdefer
.
Has option types. Can access the inner value with
fn doAThing(optional_foo: ?*Foo) void {
// do some stuff
if (optional_foo) |foo| {
doSomethingWithFoo(foo);
}
// do some stuff
}
Not sure entirely how this works. Here it's clear foo
must be associated with optional_foo
. On the other hand we new name, and how does this work with multiple variables, or a more complex expression? We perhaps often don't need a new variable name, although in some circumstances you might want to to name either. So...
if (optional_foo) {
// can use as contained value, because the if expression proves it hold the value
doSomethingWithFoo(optional_foo);
}
// `as` is probly not right. `reify`, or perhaps some syntax
if (optional_foo as foo) {
doSomethingWithFoo(\foo);
}
// say. Where => is true if option is true, and if it's true variable foo holds the contained value.
if (optional_foo => foo) {
doSomethingWithFoo(\foo);
}
Is a concrete value coerced into an optional type?
Any function that does memory allocation, takes an allocator. That seems kind of dull in practice. I like the context
idea, where it holds an allocator (and perhaps other stuff, like a log etc). This means that the caller doesn't know that the function can consume memory, though.
Perhaps that is indicated in some effects system.
Looks like in the syntax uses ! to indicate an error or type. For example
fn charToDigit(c: u8) !u8 {
const value = switch (c) {
'0'...'9' => c - '0',
'A'...'Z' => c - 'A' + 10,
'a'...'z' => c - 'a' + 10,
else => return error.InvalidCharacter,
};
return value;
}
In the use of this example zig does determine all possible return values (?) and require they are all covered. Not sure what error is yet, if it's an enum then that's simple, but an error system would seem to need to be able to be extendable.
The use of integer types of arbitrary sizes, does give some nice flexibility and control. What seems to be missing is how define a backing. You could get something like this if you could do
struct SomeType : i32
{
i1 bit;
i7 otherSuff;
i16 yetMore;
}
Then if you can make @transparent
within use. I think Odin used using
for @transparent
.
struct OtherType
{
@transparent SomeType t;
int otherType;
}
This still might not give the flexibility desired, as doesn't allow a value to span byte/short/word/long etc. Probably covers the majority of scenarios.
Nice to see c_
prefixed type that match up with c ABI.
The use of break to be able to return a value. Seems clunky that it needs a label, but something like that is necesary to indentify where to return to. Perhaps a keyword could be used such it is not necessary to specify. The mechansim is a little like a lambda/closure.
var declarations at the top level or in struct declarations are stored in the global data section.
This explains the odd static variable observation - the var
prefix makes it global. It seems odd that var in a function is a stack variable, but perhaps the argument is that the context (function/struct) makes that make sense.
Read:
Has a section around issues with recursion.
Makes claims around safely handling memory exhaustion. Not sure I'm buying it.
Interesting seeing all the targets enumerated from LLVM. Seems to be
On trying out with compiler explorer, doing something simple with shifing. I found
fn someFunc(a : i32) i32 {
// Doesn't work, because rhs << is u5. Which is not unreasonable per se, but requires
return i << a;
}
This worked with...
export fn someFunc(num: i32) i32 {
return @as(i32, 1) << @truncate(u5, @bitCast(u32, num));
}
Hmm, it's a little convoluted though. Say compared to
int someFunc(int i) { return 1 << (i & 0x1f); }