Repository navigation
zig updates nov-09-2016 #212
Copy link
Copy link
Closed
Labels
enhancementSolving this issue will likely involve adding new logic or components to the codebase.Solving this issue will likely involve adding new logic or components to the codebase.
Milestone
Description
Notes from a 5 hour long phone call with @thejoshwolfe.
I'll close this issue when I finish implementing and/or moving all summary items to appropriate new/existing github issues.
Note that source code below is all brainstorming and may or may not reflect actual syntax and ideas.
Summary:
* named return types solves pointer-to-self.
* no more error union. instead %-> and you must catch errors with %%.
* no tuples are in the future, instead we have multiple return types - possibly named.
* %if% (const value, const value2 = div(3, 2)) {
} else |err| switch (err) {
DivByZero => {},
}
* ?if? (a = b) {}
* all expressions and return types have a number of expressions.
* assembly syntax returns 0 or more expressions
* explicit void cannot be ignored.
* variable declarations are statements not expressions.
* byval copyable parameters and return values. @setIsCopyable(this, true)
* (...name: []const Type) var args. can have Type=var for heterogeneous. (accept https://github.com/andrewrk/zig/issues/77#issuecomment-236307968 "alternatively")
Problems to solve:
* assigning one field to the address of another in a struct initialization member
struct Foo {
one: &i32,
two: i32,
fn init() -> Foo {
Foo{
.two = 1234,
.one = &this.two,
}
}
fn init() -> result: Foo {
result = Foo{
.two = 1234,
.one = &this.two,
};
}
fn init() -> result: %Foo {
if (something) return error.BadError;
result = Foo{
.two = 1234,
.one = &this.two,
};
}
fn init() %-> result: Foo {
if (something) return error.BadError;
result = Foo{
.two = 1234,
.one = &this.two,
};
}
}
// example of %return usage being handy
https://github.com/andrewrk/zig/blob/master/std/elf.zig#L186
// broken because one points to invalid memory
var foo = Foo.init();
error DivByZero;
error DivByZero;
/// this comment applies to bar
error DivByZero;
fn bar() {}
/// doc comment applies to div
error DivByZero; // no problemo
fn div(numerator: i32, denominator: i32)
%-> (quotient: i32, remainder: i32)
{
if (denominator == 0) return error.DivByZero;
quotient = numerator / denominator;
remainder = numerator % denominator;
}
fn main() %-> void {
if (const value, const value2 %%= div(3, 2)) {
} else |err| {
switch (err) {
DivByZero => {},
}
}
?if? (const value = maybe_thing) {
}
%if% (const value, const value2 = div(3, 2)) {
} else |err| switch (err) {
DivByZero => {},
}
foo.one, foo.two = %return% div(3,2);
var x2, var y2 = %return% div(3,2);
var x2, var y2 = div(3,2) %% |err| {
return err == error.ThatOneError;
};
var foo = Foo.init();
var foo = Foo{...};
var foo = Foo.init() %% Foo{...};
var foo = Foo.init() %% {
foo = Foo{...};
};
switch (some_enum_value) {
One => |blah| {
},
}
var a = getTime() %% |err| {
printf("error: %s", @errorName(err));
};
var a = getTime() %% {-1};
var a = getTime() %% {
printf("WARNING: can't get time\n");
-1
};
const x3, const y3 = 💩return div(3, 2);
const x: i32;
const y: i32;
irrelevant_stuff();
if (some_condition) {
x = 1234;
y = 5678;
} else {
x = 9101;
y = 1314;
}
const x: i32, const y: i32 = if (some_condition) {
1234, 5678
} else {
9101, 1314
};
if (some_condition) {
1234
} else {
9101
};
_ = 1234;
_ = aFunction(); // error calling pure function for side effects
foo.one, foo.two, _ = if (some_condition) {
1234, 5678, 1
} else {
const a, const b = %return div(3,2);
1, a, b
};
b, a = a, b;
b, a = noop(a, b);
b, a = {
f();
a, b
};
b, a = f()(a, b), f()(a, b);
b = f()(a, b);
a = f()(a, b);
}
fn noop(a: &const i32, b: &const i32) -> (c: i32, d: i32) {
c = *a;
d = *b;
}
fn aFunction() {
if (a) return sideEffects(1);
sideEffects(2);
}
fn sideEffects(x: i32) { @breakpoint(); }
1. people should be able to avoid `undefined`
2. initializing static data should be same as initializing runtime data
* asm expressions should be able to return multiple values
// potentially problematic because only at entry point to this first asm expression do we have guarantee about what registers hold
want this to be atomic
argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize));
argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
argc, argv = asm(
\\mov (%%rsp), %[argc]
\\lea 0x8(%%rsp), %[argv]
: [argc, argv] "=r" (-> argc: usize, argv: &&u8)
);
http://llvm.org/docs/LangRef.html#inline-assembler-expressions
http://llvm.org/docs/LangRef.html#extractvalue-instruction
test cases:
matrix265x265.transform(t).transform(t2).scale(-1);
// will it blend?
const result = vector.add(1, 2).add(-1, -3);
fn bad() -> &i32 {
var x: i32 = undefined;
return &x; // can the compiler catch this?
}
struct Vec2(T: type) {
const Self = this;
@setIsCopyable(Self, true);
x: T,
y: T,
pub fn add(self: &const Self, other_x: T, other_y: T) -> Self {
Self{
.x = self.x + other_x,
.y = self.y + other_y,
}
}
pub fn add(self: &const Self, other_x: T, other_y: T) -> (result: Self) {
result.x = self.x + other_x;
result.y = self.y + other_y;
}
}
type CDW = []u8;
type StdOutPipe = i32;
type IsRedirect = void;
const isRedirect = IsRedirect{};
struct ActualProcess {
cwd: []u8,
stdout_pipe: i32,
isRedirect: bool,
}
pub fn createProcess(...args) {
var ActualProcess: Process = undefined;
inline for (args) |arg| {
inline switch (@typeOf(arg)) {
CDW => {},
}
}
}
myDsl(nameOfThing, anotherOne);
createProcess(CWD("/"), StdOutPipe(1), isRedirect);
fn anotherFn(a: i32, b: i32) {}
pub fn printf(os: &OutStream, inline format: []const u8,
...args: []const var) -> %usize
{
anotherFn(args[0], args[1]) //assuming args[0] and args[1] is type i32
inline for (args) |arg| {
if (arg %= @constEval(arg)) {
// compile time
new_fmt ++= asdf;
} else {
// runtime
}
}
}
pub fn print_error(error_code: u32, inline fmt: []const u8, ...args: []var) {
const error_name = error_names[error_code];
// this assumes the ++ operator works on compile-time constant-length arrays
// with variable values at each index.
const new_args = []var{error_name, error_code} ++ args;
io.stderr.printf("ERROR: %s(%d): " ++ fmt ++ "\n", ...new_args);
}
// alternatively:
pub fn print_error(error_code: u32, inline fmt: []const u8, ...args: []var) {
const error_name = error_names[error_code];
// this assumes a relaxed requirement on passing `...` arguments.
io.stderr.printf("ERROR: %s(%d): " ++ fmt ++ "\n", error_name, error_code, ...new_args);
}
// If we want the List class to expose ensure_capacity() to callers,
// we can also offer an unchecked add method that skips the capacity check:
pub fn add_unchecked(list: &Self, ...items: []const T) {
for (items) |item, i| {
list._buf[list._size + i] = item;
}
list._size += items.len;
}
// and then the common add method can reuse the above by forwarding the args:
pub fn add(list: &Self, ...items: []const T) {
list.ensure_capacity(list._size + items.len);
list.add_unchecked(...items);
}
fn foo() {}
fn boo() -> void {
// where's your return?
return void{};
}
// stuff that you can do in status quo zig that makes no sense
fn foo() {
var x: i32 = 0;
return x = 1;
}
fn put(k: K, v: V) -> V {
}
struct Set(inline K: type) {
map: Map(K, void),
fn add(s: &Self, k: K) {
_ = map.put(k, void{});
}
}
foo(); // good
boo(); // ERROR: ignoring the return type
_ = boo(); // good
fn whatever() % {}
fn whatever() %-> i32 {}
💩return💩
💩if💩
+%
-%
*%
<<%
<<%=
if (x 💩=
fn div(numerator: i32, denominator: i32)
💩-> (quotient: i32, remainder: i32)
{
}
var a, var b = div(3, 2) 💩💩
fn draw_particle(t: &Tetris, p: Particle) {
const model = mat4x4_identity
.translate_by_vec(p.pos)
.rotate(p.angle, p.axis)
.scale(p.scale_w, p.scale_h, 0.0);
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementSolving this issue will likely involve adding new logic or components to the codebase.Solving this issue will likely involve adding new logic or components to the codebase.
Activity