ZIG programming language.

Electronic Computer Control Unit -> Instruction Cycle -> Instruction Decoder -> Control Signals -> ...

CODE EnCODE DeCODE
First we need CODE, then CODE based EnCODE is possible, then CODE based DeCODE of EnCODE is possible.

Layer 1 : RISC-V Machine Code, ..., (ARM, x86_?, POWER, ... Machine codes)
Layer 2 : RISC-V Assembly, ...(ARM, x86_?, POWER, ... Assembly codes)
Layer 3 : RISC-V Portable Assembly GCC IR gimple, LLVM IR, ...
Layer 4 : c, c--, cmm, c-like subsets, fortran, ...
Layer 5 : c++, objective-c, objective-c++, d, rust, ... , Nim, Crystal, Zig, V, ..., go, ada, ...
Layer 6 : Based on previous layers language apps like JVM, BEAM, CLR(.net), MoarVM, WebAssembly, JS, Python, PHP, Perl, Ruby,...

so from layer4,5 layer languages need to be ordered as per coherent higher order
 
I think Zig’s home page does a great job of explaining the bullet point reasons why you might want to use it.

I haven’t written any zig yet. One thing I’m curious about regarding allocators being explicitly passed in: is that by convention, or language enforced? Because you need to initialize the allocator somewhere, in which case it’s not being passed in. Though I could see how the compiler could check to make sure that the allocator is released in the same scope it’s created in, which would be good.

I’m pretty interested in. I also hope that we see a language between Zig and Rust. Memory safety is explicitly not a goal of Zig - its strategy is to reduce memory errors by making it easier to do the right thing. Rust on the other hand guarantees memory safety as much as it can, but is pretty complex. I don’t know if it’s possible to enforce memory safety with a less complex language, but that’s what I’d like to see.
 
By convention.
See this topic on Zig's forum.
Cool, thanks for that.

I wonder if it's something a linter could catch. Rust has (at least) two mechanisms for easing its error checking: unwrap() and the try operator. They are convenient when writing new code and I don't yet want to have to think about all possible error cases. But I want to handle those properly at some point, so I can use the linter to check for those usages and replace them with robust error handling.

Presumably zig could do something similar and check for allocators outside of main, or otherwise blessed functions.
 
How zig looks like,
Code:
cat main.zig 
const std = @import("std");
const deb = std.debug;
const io = std.io;
const pri = deb.print;
const stdoutf = io.getStdOut().writer();
var bw = io.bufferedWriter(stdoutf);
const stdout = bw.writer();

const arrayList = std.ArrayList;
const sheap = std.heap;
const config=.{.safety=true};
var gpa = sheap.GeneralPurposeAllocator(config){};
const gpaallocator = gpa.allocator();

const Vec = struct {
    x: f32,
    y: f32,

    pub fn init(xa:f32,ya:f32) Vec {
        return Vec { .x=xa + 0.1 , .y=ya + 0.2};
    }

    pub fn printx(v:Vec) void {
        pri("{e}\n",.{v.x});
    }

};

const Month = enum {
    January,
    February,
    March,
};

fn myadd(a:i32,b:i32) i32 {
return a+b;
}

fn myprint(s:[] const u8) void {
    pri("string:{s}",.{s});
}

pub fn range(len: usize) []const u0 {
    return @as([*]u0, undefined)[0..len];
}

const  myunion = union(enum) {
    i:i32,
    f:f32,
};

fn printunion(u:myunion)  void {
    switch(u) {
        .i => |i| pri("Integer : {d}\n",.{i}),
        .f => |f| pri("Float : {e}\n",.{f}),
    }
}

const myerrors= error { MyError,MyError2};

fn testerror(succeed:bool) myerrors!bool {
    if(!succeed) {
        return myerrors.MyError; 
    }
    else {
        return true;
    }

}

pub fn main() !void {

    var arrx:[10]u32=undefined;
    arrx[2]=4;
    pri("{d}\n",.{arrx[2]});

    var x: i32=321;
    var px: *i32=&x;
    pri("{d}\n",.{px.*});

    var ov: ?u32=null;
    if(ov)|value|{
        pri("Value : {d}\n",.{value});
    }
    else {
        pri("isnull\n",.{});
    }
    ov=88;
    if(ov)|value|{
        pri("Value : {d}\n",.{value});
    }
    else {
        pri("isnull\n",.{});
    }

    const  r:bool = testerror(false) catch |err| blk: {
        if (err == myerrors.MyError) {
            break :blk false;
        }
        else {
            return;
        }
    };
    pri("{any}\n",.{r});

    switch (15) {
        0...10 => pri{"0-10\n",.{}},
        15 => pri("15\n",.{}),
        20 => pri("20\n",.{}),
        else =>  pri("Error\n",.{}),
    }

    pri("Hello World1\n", .{});
    try stdout.print("Hello World2\n", .{});
    try bw.flush();

    const myvec = Vec.init(2.0,3.0);
    pri("{e}\n", .{myvec.x});
    myvec.printx();

    var vv: i32 = 123;
    pri("{d}\n", .{vv});

    var month:Month=.January;
    pri("Month:{}\n",.{month});

    pri("Add : {d}\n", .{myadd(123,456)});

    myprint("Mystring\n");

    const m1:myunion=myunion{.f=2.3};
    const m2:myunion=myunion{.i=5};
    printunion(m1);
    printunion(m2);

    var list = arrayList(u8).init(gpaallocator);
    defer list.deinit();
    try list.append('C');
    try list.append('A');
    try list.append('T');
    _ =list.pop();
    for (list.toOwnedSlice()) |elem,index| {
        pri("by val: {d} : {c} \n", .{index,elem});
    }
 
Oh, btw..

Since this forum is FreeBSD dedicated,
I'd like to note just one little feature
I like in FreeBSD API (as opposed to Linux API).

It's about adding a fd (file descriptor) to a set of file descriptors
being watched by an application program.

In FreeBSD when adding a fd to "watched fds' set"
in case of it's already there FreeBSD kernel just accepts it.

In Linux such a behavior of an app is an error,
and when I tried to construct an abstraction
above epoll/kqueue in Zig, I came up with this workaround:


Code:
fn enableEventSource(self: *EventQueue, es: *EventSource, ek: EventKind) !void {

        const FdAlreadyInSet = os.EpollCtlError.FileDescriptorAlreadyPresentInSet;
        var em: u32 = if (.can_read == ek) (EPOLL.IN | EPOLL.RDHUP) else EPOLL.OUT;
        em |= EPOLL.ONESHOT;

        var ee = EpollEvent {
            .events = em,
            .data = EpollData{.ptr = @ptrToInt(es)},
        };

        // emulate FreeBSD kqueue behavior
        epollCtl(self.fd, EPOLL.CTL_ADD, es.id, &ee) catch |err| {
            return switch (err) {
                FdAlreadyInSet => try epollCtl(self.fd, EPOLL.CTL_MOD, es.id, &ee),
                else => err,
            };
        };
    }


I did not explore Zig in FreeBSD,
I only had some some little experience with D in this OS,
but I hope that will be useful for someone anyhow.

And still I think that a language with GC (no matter, ARC or "true") is not a C competitor.
 
A bosh like that can easily be written in any lang regardless of whether $lang is "good"/"bad", "popular"/"unpopular", "modern"/"ancient" and so on. Where did you find those mussy exercises? :)
I converted the website to a pdf using "pandoc".
 

Attachments

  • zig1.pdf
    1.6 MB · Views: 51
  • zig2.pdf
    148.9 KB · Views: 68
  • zig3.pdf
    169.6 KB · Views: 35
Nope, it is much more useful to learn FORTH.
Now that's a name I've not heard in a long time. A long time. Instead of adding Rust (or Zig) to base, let's rewrite the kernel and utilities in Forth. Oh wait, BTDT, got the T-shirt. I vaguely remember having an EPROM (or was it a tape?) that allowed booting Forth on a 6809-based microcomputer. It was sort of fun.
 
Back
Top