Hello :))
I am building a Discrete-Event simulation of a social network (cannot share the code to it yet..), and this idea came to me. To schedule the time between events, I use runtime dynamic dispatching reading from a json config file (see the distributions library, the json part of the README for more context) and to give the user the choice if the traces should be written to file or not. Let’s focus on the file example for a minute, my code is filled with:
if (simconf.trace_to_file) { // write the trace }
which cannot be optimized, as the variable trace_to_file is read from a json at runtime. Also, I cannot embed the config file into the build system, as I want this to be just a single executable, the end user should be able to just pass the desired configuration and the simulation to run —make them run zig build is not an option.
Now, an idea crossed in my head… Could I make a Zig program that received the configuration file, read it ({"trace_to_file": false}) and knowing that information, could compile the simulation removing the if (simconf.trace_to_file) checks?
A silly concrete example mimicking the situation I am at:
const std = @import("std");
const Io = std.Io;
// json equivalent struct
const Conf = struct {
write_to_file: bool,
};
pub fn main(init: std.process.Init) !void {
const arena: std.mem.Allocator = init.arena.allocator();
const args = try init.minimal.args.toSlice(arena);
if (args.len <= 4) {
std.debug.print("Usage: n a b config.json\n", .{});
std.process.exit(1);
}
const n = try std.fmt.parseInt(u64, args[1], 10);
const a = try std.fmt.parseInt(u64, args[2], 10);
const b = try std.fmt.parseInt(u64, args[3], 10);
// load json
const content = try std.Io.Dir.cwd().readFileAlloc(init.io, "conf.json", arena, .unlimited);
defer arena.free(content);
const options = std.json.ParseOptions{ .ignore_unknown_fields = true };
const parsed_result = try std.json.parseFromSlice(Conf, arena, content, options);
const conf = parsed_result.value;
// In order to do I/O operations need an `Io` instance.
const io = init.io;
var stdout_buffer: [1024]u8 = undefined;
var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer);
const stdout_writer = &stdout_file_writer.interface;
try stdout_writer.print("Computing the {d}-th fibonacci number starting with ({d}, {d})\n", .{ n, a, b });
try stdout_writer.flush();
const nth = try fibonacci(init.io, a, b, n, conf);
try stdout_writer.print("nth: {d}\n", .{nth});
try stdout_writer.flush(); // Don't forget to flush!
}
/// Computes the n-th fibonacci number
fn fibonacci(io: std.Io, a: u64, b: u64, n: u64, conf: Conf) !u64 {
var buffer: [64 * 1024]u8 = undefined;
const file = try std.Io.Dir.cwd().createFile(io, "./fib.txt", .{ .read = false });
defer file.close(io);
var file_writer = file.writer(io, &buffer);
const writer = &file_writer.interface;
var f_i2: u64 = a;
var f_i1: u64 = b;
// AIMING TO REMOVE THIS
if (conf.write_to_file) {
try writer.print("{d}\n", .{f_i2});
try writer.print("{d}\n", .{f_i1});
}
for (2..n) |_| {
const f_i = f_i2 + f_i1;
// AIMING TO REMOVE THIS
if (conf.write_to_file) {
try writer.print("{d}\n", .{f_i});
}
f_i2 = f_i1;
f_i1 = f_i;
}
// AIMING TO REMOVE THIS
if (conf.write_to_file) {
try writer.flush();
}
return f_i1;// AIMING TO REMOVE THIS
}
The point would be that the if inside the fibonacci code could get optimized away by making the two programs setup.
Idk if I am just delulu, but I don’t know where even to stat to try to test this, and that’s why I am asking here ![]()