bmaxa
Legenda
- Poruka
- 70.808
Zig je novi jezik, koji ima za nameru da zameni C.
Inspiracija je C,Rust i Go.
Dok je Go jezik viseg nivoa koji ima za cilj da zameni Python,
kao kompajlirani jezik samim tim i efikasniji, Rust tezi da
zameni C++ kao sigurniji jezik, Zig zeli da zameni C uzimajuci
elemente i Rust-a i Go-a.
Dakle, iz Rust-a je uzet error handling(tagovane unije) a iz Go-a,
neke konstrukcije kao sto su gorutine ovde implementirane
kao korutine(async/await), pa i defer koji dodje kao zamena za C++ RAII.
Jezik ne koristi C lib(libc) nego ima svoj, tako da je mali.
Interesantna stvar je da strukture identifikuju tip sa imenom
varijable koja dobija vrednost iste, ili f-je koja ih vraca.
Potom nema odredjeni alokator vec se to uzima iz biblioteke,
po izboru i potrebi.
Vise o jeziku: https://ziglang.org/documentation/master/
Na kraju da dam dva primera kratkih programa, pa onako da
se stvori neki utisak.
Prvi je program k-nucleotide sa computer language benchmark
strane.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/description/knucleotide.html#knucleotide
Kompajlira se sa: zig build-exe k-nucleotide.zig -O ReleaseFast --library c
Drugi program je primer servera i klijenta, koji koristi async pozive.
Async su ovde korutine, znaci bez obzira sto deluje da ima vise threadova,
zapravo se sve odvija u jednom threadu.
Interesantna stvar je da bi se dobio non blocking io mora se definisati
ispred main-a. Kod je prilicno ilustrativan, tako da mislim da je sve jasno.
Inace async/await je masovno popularno tako da skoro nema novog jezika ko to nema ili
nije skoro uveo.
Kompajlira se sa: zig build-exe test.zig -O ReleaseFast
Sve je kompajlirano na Linux-a ali bi trebalo da radi i na Windows-u (ili ne znam).
U svakom slucaju prvi put da vidim jezik koji ima za cilj da zameni C.
Inspiracija je C,Rust i Go.
Dok je Go jezik viseg nivoa koji ima za cilj da zameni Python,
kao kompajlirani jezik samim tim i efikasniji, Rust tezi da
zameni C++ kao sigurniji jezik, Zig zeli da zameni C uzimajuci
elemente i Rust-a i Go-a.
Dakle, iz Rust-a je uzet error handling(tagovane unije) a iz Go-a,
neke konstrukcije kao sto su gorutine ovde implementirane
kao korutine(async/await), pa i defer koji dodje kao zamena za C++ RAII.
Jezik ne koristi C lib(libc) nego ima svoj, tako da je mali.
Interesantna stvar je da strukture identifikuju tip sa imenom
varijable koja dobija vrednost iste, ili f-je koja ih vraca.
Potom nema odredjeni alokator vec se to uzima iz biblioteke,
po izboru i potrebi.
Vise o jeziku: https://ziglang.org/documentation/master/
Na kraju da dam dva primera kratkih programa, pa onako da
se stvori neki utisak.
Prvi je program k-nucleotide sa computer language benchmark
strane.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/description/knucleotide.html#knucleotide
Kod:
const std = @import("std");
const FACTOR: u32 = 16;
const HashMap = std.StringHashMap(u32);
const Val = struct { key: u32, value: []const u8 };
fn kvLessThan(_: void, lhs: Val, rhs: Val) bool {
return lhs.key > rhs.key;
}
var def = HashMap.Entry{ .key = "", .value = 0 };
fn calculate(allocator: *std.mem.Allocator, poly: []const u8, size: u32) !HashMap {
var hash = HashMap.init(allocator);
const A = struct {
allocator: *std.mem.Allocator,
poly: []const u8,
size: u32,
i: u32,
hash: HashMap,
const Self = @This();
fn ex(self: *Self) void {
self.hash = HashMap.init(self.allocator);
{
var key: u64 = 0;
var j: u32 = self.i;
while (j < self.poly.len + 1 - self.size) : (j += FACTOR) {
var entry = self.hash.getOrPutValue(self.poly[j .. j + self.size], 0) catch &def;
entry.value += 1;
}
}
}
};
var i: u32 = 0;
var frame: [FACTOR]A = undefined;
var threads: [FACTOR]*std.Thread = undefined;
while (i < FACTOR) : (i += 1) {
frame[i] = .{
.allocator = allocator,
.poly = poly,
.size = size,
.i = 0,
.hash = undefined,
};
frame[i].i = i;
threads[i] = try std.Thread.spawn(&frame[i], A.ex);
}
i = 0;
while (i < FACTOR) : (i += 1) {
threads[i].wait();
var ht = frame[i].hash;
defer ht.deinit();
var iterator = ht.iterator();
while (iterator.next()) |entry| {
var e = try hash.getOrPutValue(entry.key, 0);
e.value += entry.value;
}
}
return hash;
}
fn generateFrequenciesForLength(allocator: *std.mem.Allocator, poly: []const u8, comptime desired_length: usize, output: []u8) !void {
var hash = try calculate(allocator, poly, desired_length);
defer hash.deinit();
var list: []Val = try allocator.alloc(Val, hash.count());
defer allocator.free(list);
var i: usize = 0;
var it = hash.iterator();
while (it.next()) |entry| {
list[i] = .{ .key = entry.value, .value = entry.key };
i += 1;
}
std.sort.sort(Val, list, {}, kvLessThan);
var position: usize = 0;
for (list) |*entry| {
const slice = try std.fmt.bufPrint(output[position..], "{} {d:.3}\n", .{
entry.value,
100.0 * @intToFloat(f64, entry.key) / @intToFloat(f64, poly.len - desired_length + 1),
});
position += slice.len;
output[position] = 0;
}
}
fn generateCount(allocator: *std.mem.Allocator, poly: []const u8, comptime olig: []const u8, output: []u8) !void {
var hash = try calculate(allocator, poly, olig.len);
defer hash.deinit();
{
const count = if (hash.getEntry(olig)) |entry| entry.value else 0;
const slice = try std.fmt.bufPrint(output, "{}\t{}", .{ count, olig });
output[slice.len] = 0;
}
}
pub fn main() anyerror!void {
var allocator = std.heap.c_allocator;
var stdout_file = std.io.getStdOut();
var stdout_out_stream = stdout_file.outStream();
var buffered_stdout = std.io.bufferedOutStream(stdout_out_stream);
defer _ = buffered_stdout.flush() catch {};
const stdout = buffered_stdout.writer();
var stdin_file = std.io.getStdIn();
var stdin_in_stream = stdin_file.inStream();
var buffered_stdin = std.io.bufferedInStream(stdin_in_stream);
const stdin = buffered_stdin.reader();
var buffer: [4096]u8 = undefined;
while (true) {
const line = try stdin.readUntilDelimiterOrEof(buffer[0..], '\n');
if (line) |line1| {
if (std.mem.startsWith(u8, line1, ">THREE")) {
break;
}
} else {
break;
}
}
var poly = std.ArrayList(u8).init(allocator);
defer poly.deinit();
while (true) {
const line = try stdin.readUntilDelimiterOrEof(buffer[0..], '\n');
if (line) |line1| {
for (line1) |c| {
try poly.append(std.ascii.toUpper(c));
}
} else {
break;
}
}
const poly_shrunk = poly.toOwnedSlice();
const counts = [_]u8{ 1, 2 };
const entries = [_][]const u8{ "GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT" };
var output: [counts.len + entries.len][4096]u8 = undefined;
inline for (counts) |count, i| {
try generateFrequenciesForLength(allocator, poly_shrunk, count, output[i][0..]);
}
inline for (entries) |entry, i| {
try generateCount(allocator, poly_shrunk, entry, output[i + counts.len][0..]);
}
for (output) |entry| {
try stdout.print("{s}\n", .{entry[0..]});
}
}
Kompajlira se sa: zig build-exe k-nucleotide.zig -O ReleaseFast --library c
Drugi program je primer servera i klijenta, koji koristi async pozive.
Async su ovde korutine, znaci bez obzira sto deluje da ima vise threadova,
zapravo se sve odvija u jednom threadu.
Interesantna stvar je da bi se dobio non blocking io mora se definisati
Kod:
pub const io_mode = .evented;
Inace async/await je masovno popularno tako da skoro nema novog jezika ko to nema ili
nije skoro uveo.
Kod:
const std = @import("std");
const net = std.net;
const mem = std.mem;
const testing = std.testing;
pub const io_mode = .evented;
pub fn main() !void {
if (!std.io.is_async) return error.SkipZigTest;
// Ignore sigpipe
var act = std.os.Sigaction{
.sigaction = std.os.SIG_IGN,
.mask = std.os.empty_sigset,
.flags = 0,
};
std.os.sigaction(std.os.SIGPIPE, &act, null);
// TODO doing this at comptime crashed the compiler
const localhost = try net.Address.parseIp("127.0.0.1", 6666);
var server = net.StreamServer.init(net.StreamServer.Options{ .reuse_address = true });
defer server.deinit();
try server.listen(localhost);
var server_frame = async testServer(&server);
var client_frame = async testClient(server.listen_address);
try await server_frame;
try await client_frame;
}
fn testClient(addr: net.Address) anyerror!void {
const socket_file = try net.tcpConnectToAddress(addr);
defer socket_file.close();
var buf: [100]u8 = undefined;
const len1 = try socket_file.write("abcd");
const len = try socket_file.read(&buf);
const msg = buf[0..len];
testing.expect(mem.eql(u8, msg, "hello from server\n"));
}
fn testServer(server: *net.StreamServer) anyerror!void {
while (true) {
var client = try server.accept();
var frame = async handle(client);
resume frame;
await frame catch |err| {
std.debug.warn("Disconnected {}: {}\n", .{ client, err });
};
}
}
fn handle(client: anytype) !void {
defer client.file.close();
const stream = client.file.outStream();
const readstream = client.file.inStream();
suspend;
var buf: [256]u8 = undefined;
_ = try readstream.read(buf[0..]);
_ = try stream.print("hello from server\n", .{});
}
Kompajlira se sa: zig build-exe test.zig -O ReleaseFast
Sve je kompajlirano na Linux-a ali bi trebalo da radi i na Windows-u (ili ne znam).
U svakom slucaju prvi put da vidim jezik koji ima za cilj da zameni C.