Could someone explain how this works: const print = #import("std").debug.print; - zig

How can this const print variable behave like a function?
const print = #import("std").debug.print;
print("hello, world", .{});
I understand you can assign expressions to variables. But this seems to behave like a precompiler macro in c/c++, I wouldn't have guessed that.
Is it because "all variables declared in a comptime expression are implicitly comptime variables" and # makes it a comptime expression, so it is evaluated before compilation, much like a macro would in c?
Could someone elaborate a bit? This seems a very powerful feature.

# does not indicate a comptime expression; rather # prefixes built-in functions in Zig. #import returns a struct that provides access to the declarations made public by the imported file.
The expression #import("std").debug.print evaluates to the print function defined in the standard library file std/debug.zig; it is not the expression that is assigned to print in the posted code, but the function. That is, the posted code works because print in OP code is actually a function. This can be seen by running the code below:
const print = #import("std").debug.print;
pub fn main() void {
print("#TypeOf print: {}\n", .{ #TypeOf(print) });
}
Results:
$ zig run print_type.zig
#TypeOf print: fn(comptime []const u8, anytype) void
Function Assignment
OP has asked for another example of assigning a function that is not imported to an identifier:
const print = #import("std").debug.print;
fn my_function(msg: []const u8) void {
print("{s}\n", .{ msg });
}
const my_function_alias = my_function;
pub fn main() void {
const another_function_alias = my_function;
const yet_another_function_alias = my_function_alias;
my_function("mf");
my_function_alias("mfa");
another_function_alias("afa");
yet_another_function_alias("yafa");
}
Program output:
$ zig run function_assignment.zig
mf
mfa
afa
yafa

Related

zig externs when using zig test for wasm

I have a Zig codebase that I'm compiling to WebAssembly with a build.zig like this:
const std = #import("std");
pub fn build(b: *std.build.Builder) void {
const mode = b.standardReleaseOptions();
const lib = b.addSharedLibrary("main", "src/main.zig", b.version(0, 0, 0));
lib.setBuildMode(mode);
lib.setTarget(.{.cpu_arch = .wasm32, .os_tag = .freestanding});
lib.setOutputDir("web/dist");
b.default_step.dependOn(&lib.step);
}
Inside src/main.zig there's an extern that marks a function provided through the WebAssembly imports.
extern fn printString(message: [*]u8, length: usize) void;
This works fine when running in the browser, but I'm trying to add tests to the project, but whenever I attempt to run zig test on main.zig (or any file with extern) I get the following linker error.
MachO Flush... error(link): undefined reference to symbol '_printString'
It might be worth pointing out that nothing in my test "..." {} blocks actually touches any of these extern functions.
Is there a sane way to link to alternate implementations of these externs during tests? Or any other workarounds that would allow me to write tests?
You can use combine #import("builtin").is_test and usingnamespace to create stubs for extern functions during tests.
const builtin = #import("builtin");
pub usingnamespace if (!builtin.is_test) struct {
pub extern fn printString(message: [*]u8, length: usize) void;
} else struct {
pub fn printString(message: [*]u8, length: usize) void {
_ = message;
_ = length;
}
}
pub usingnamespace makes all the members of the struct part of the module's public struct, and during tests we just use a different struct that doesn't rely on any external functions.
Credit to mitchellh/zig-js.

How do I pass a stream or writer parameter to a function in Zig?

I'm trying to pass the output stream to a function but can't get it right. This sample code shows a couple of the things I've tried
// Attempts to pass stream or writer to a function
const std = #import("std");
pub fn main() !void {
// #1
try print1(std.io.getStdOut(), "Hello, ");
// #2
try print2(std.io.getStdOut().writer(), "world!");
}
// error: 'File' is not marked 'pub'
pub fn print1(file: std.io.File, str: []const u8) !void
{
try file.writer().print("{s}", .{str});
}
// error: expected type 'type', found 'fn(comptime type, comptime type, comptime anytype) type'
fn print2(writer: std.io.Writer, str: []const u8) !void
{
try writer.print("{s}", .{str});
}
I'm using Zig 0.10.0
The call to std.io.getStdOut() returns a File, but the File type is in the std.fs namespace. Calling std.io.getStdOut().writer() returns a Writer from the std.fs.File namespace. You could also declare the writer parameter with the anytype keyword to get type inference at the time of the function call.
Here is a modified version of OP posted code:
const std = #import("std");
pub fn main() !void {
const stdout = std.io.getStdOut();
const writer = stdout.writer();
// #1
// Pass `stdout` to a function:
try print1(stdout, "Hello, ");
// #2
// Pass a `Writer` to a function:
try print2(writer, "world!\n");
// #3
// Pass a `Writer` to a function:
try print3(writer, "Hello, again!\n");
}
fn print1(file: std.fs.File, str: []const u8) !void {
try file.writer().print("{s}", .{str});
}
// Explicit type annotation for `writer`:
fn print2(writer: std.fs.File.Writer, str: []const u8) !void {
try writer.print("{s}", .{str});
}
// The type of `writer` is inferred when the function is called:
fn print3(writer: anytype, str: []const u8) !void {
try writer.print("{s}", .{str});
}
And a sample run:
$ zig run print_stream.zig
Hello, world!
Hello, again!
io.Writer is a generic data structure. I.e. it's a function that returns a type. You cannot use it as a function argument, but you can:
Use anytype.
Use an alias, like fs.File.Writer.
Use a "proxy" type, like fs.File, on which you'll call writer().
Use full specialization, like io.Writer(fs.File, fs.File.WriteError, fs.File.write).
anytype is required for functions that must accept arbitrary writers. Otherwise, it might be nicer to use an alias or a "proxy" type.

Does Zig support the union of anonymous structs and arrays?

Is this possible in zig? And if so how would something like the following C++ code look in Zig?
template<class T>
class vec3
{
union
{
struct{ T x,y,z; };
T vec_array[3];
};
};
No, there is no such thing supported in Zig, and it is unlikely there ever will be. The closest you'll get is something like this:
const std = #import("std");
pub fn Vec3(comptime T: type) type {
return extern union {
xyz: extern struct { x: T, y: T, z: T },
arr: [3]T,
};
}
test {
var v3: Vec3(u32) = .{ .arr = .{ 42, 73, 95 } };
try std.testing.expectEqual(v3.arr[0], v3.xyz.x);
try std.testing.expectEqual(v3.arr[1], v3.xyz.y);
try std.testing.expectEqual(v3.arr[2], v3.xyz.z);
}
where the extern qualifiers here make the containers behave in accordance with the C ABI (and in the case of the union, makes it defined behavior to access any member).
See this comment under proposal #985 for a fairly comprehensive rationale on as to why "anonymous field nesting" was rejected.

Idiomatic way to wite/pass type to generic function in ziglang

This is a much simplified version of my real issue but hopefully demonstrates my question in a concise manner.
My question is about the interface to printKeys. I have to pass in the type of the data to be printed as a comptime parameter, and the easiest way to get this is to use #TypeOf on the map at the point of calling it.
Coming from C++ this seems slightly inelegant that the type can't be inferred, although I do like being explicit too.
Is there a more idiomatic way to have a generic function in zig that doesn't need this use of #TypeOf at the point of calling, or a better way to do this in general?
const std = #import("std");
fn printKeys(comptime MapType: type, data: MapType) void {
var iter = data.keyIterator();
while (iter.next()) | value | {
std.debug.print("Value is {}\n", .{value.*});
}
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var map = std.AutoHashMap(i32, []const u8).init(allocator);
defer map.deinit();
try map.put(10, "ten");
try map.put(12, "twelve");
try map.put(5, "five");
printKeys(#TypeOf(map), map);
}
use anytype. you can find more examples in zig docs (Ctrl + F) and search anytype
fn printKeys(data: anytype) void {
...
}
pub fn main() !void {
...
printKeys(map);
}

boost python overload operator ()

I would like to bind the operator() using Boost::Python but I don't really see how to do this. Consider the example:
C++:
class Queuer
{
public:
void Queuer::operator()(const qfc::Queue & iq, const qfc::Message & im) const;
void Queuer::operator()(const qfc::Agent & ia, const qfc::Message & im) const;
// some other overloaded operator() methods
};
So in a Python script, after importing the module I'm using (called qfc), I would like to do:
Python:
>>> queuer = qfc.Queuer()
// instantiating a Message an Agent and a Queue object
>>> queuer(queue,message)
>>> queuer(agent,message)
>>> ...
Would you have any idea on how to do it? maybe with boost::python call<>?
Thank you,
Kevin
When exposing the Queuer class, define a __call__ method for each Queuer::operator() member function. Boost.Python will handle the appropriate dispatching based on types. The only complexity is introduced with pointer-to-member-function syntax, as the caller is required to disambiguate &Queuer::operator().
Additionally, when attempting to pass derived classes in Python to a C++ function with a parameter of the Base class, then some additional information needs to be exposed to Boost.Python:
The base C++ class needs to be exposed with class_. For example, class_<BaseType>("Base").
The derived class needs to explicitly list its base classes when being exposed with bases_. For example, class_<DerivedType, bases<BaseType> >("Derived"). With this information, Boost.Python can do proper casting while dispatching.
Here is a complete example:
#include <iostream>
#include <boost/python.hpp>
// Mockup classes.
struct AgentBase {};
struct MessageBase {};
struct QueueBase {};
struct SpamBase {};
struct Agent: AgentBase {};
struct Message: MessageBase {};
struct Queue: QueueBase {};
struct Spam: SpamBase {};
// Class with overloaded operator().
class Queuer
{
public:
void operator()(const AgentBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Agent." << std::endl;
}
void operator()(const QueueBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Queue." << std::endl;
}
void operator()(const SpamBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Spam." << std::endl;
}
};
/// Depending on the overlaod signatures, helper types may make the
/// code slightly more readable by reducing pointer-to-member-function syntax.
template <typename A1>
struct queuer_overload
{
typedef void (Queuer::*type)(const A1&, const MessageBase&) const;
static type get(type fn) { return fn; }
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose only the base class types. Do not allow the classes to be
// directly initialized in Python.
python::class_<AgentBase >("AgentBase", python::no_init);
python::class_<MessageBase>("MessageBase", python::no_init);
python::class_<QueueBase >("QueueBase", python::no_init);
python::class_<SpamBase >("SpamBase", python::no_init);
// Expose the user types. These classes inerit from their respective
// base classes.
python::class_<Agent, python::bases<AgentBase> >("Agent");
python::class_<Message, python::bases<MessageBase> >("Message");
python::class_<Queue, python::bases<QueueBase> >("Queue");
python::class_<Spam, python::bases<SpamBase> >("Spam");
// Disambiguate via a varaible.
queuer_overload<AgentBase>::type queuer_op_agent = &Queuer::operator();
python::class_<Queuer>("Queuer")
// Disambiguate via a variable.
.def("__call__", queuer_op_agent)
// Disambiguate via a helper type.
.def("__call__", queuer_overload<QueueBase>::get(&Queuer::operator()))
// Disambiguate via explicit cast.
.def("__call__",
static_cast<void (Queuer::*)(const SpamBase&,
const MessageBase&) const>(
&Queuer::operator()))
;
}
And its usage:
>>> import example
>>> queuer = example.Queuer()
>>> queuer(example.Agent(), example.Message())
Queuer::operator() with Agent.
>>> queuer(example.Queue(), example.Message())
Queuer::operator() with Queue.
>>> queuer(example.Spam(), example.Message())
Queuer::operator() with Spam.
Thanks for your help.
Actually I've already tested the static cast solution. In reality, I need to pass a qfc::lqs::Message or qfc::lqs::Agent or qfc::lqs::Spam when invoking queuer(). qfc::lqs::Message for example, as for qfc::lqs::Agent inherit from qfc::Message and qfc::Agent respectively.
So can I "cast" qfc::lqs::Message, qfc::lqs::Agent and qfc::lqs::Spam to qfc::Message, qfc::Agent and qfc::Spam when invoking the operator() so that the signature corresponds to operator() ?
This to avoid the error shown below:
error: invalid static_cast from type '<unresolved overloaded function type>' to type 'void (qfc::lqs::Queuer::*)(const qfc::lqs::Queue&, const qfc::lqs::Message&)const'

Resources