Declaring pointer to function - zig

I found some (a bit strange) feature of zig when played with function pointers.
Here is an example which I beleive is written as implied.
const std = #import("std");
const print = std.debug.print;
const aFunc = fn (x: i32) void;
fn theFunc(x: i32) void {
print("have {}\n", .{x});
}
pub fn main() void {
const f: aFunc = theFunc;
f(3);
}
This code compiles and runs Ok.
Now change it like this.
const std = #import("std");
const print = std.debug.print;
const aFunc = fn someFunc (x: i32) void;
fn theFunc(x: i32) void {
print("have {}\n", .{x});
}
pub fn main() void {
const f: aFunc = theFunc;
f(3);
}
This code is also Ok, but shouldn't the compiler emit error/warning about someFunc?
This name is useless - when I tried to use it instead of aFunc there was an compilation error.
Compiler version:
$ /opt/zig/zig version
0.10.0-dev.3431+4a4f3c50c
It looks like the zig source parser treats
const aFunc = fn someFunc (x: i32) void;
as if it is function definition, but silently drops someFunc.

Related

compiler error with calling type method that takes empty context

I'm trying to call SomeClass().call, but am running into compiler errors.
Specifically, running tests for
const std = #import("std");
test "doing a thing" {
{
const calc_result = SomeClass().call(.{});
try std.testing.expectEqual(calc_result, 42);
}
}
fn SomeClass() type {
return struct {
fn call(context: .{}) u32 {
_ = context;
return 42;
}
};
}
results in the error message
src/test.zig:12:17: error: expected type 'type', found '#TypeOf(.{})'
fn call(context: .{}) u32 {
^~~~~~~
referenced by:
test.doing a thing: src/test.zig:5:40
remaining reference traces hidden; use '-freference-trace' to see all reference traces
How do I call a generic type method that takes an empty context?
What you're doing is equivalent to fn foo(value: 0) void {}. Which is obviously wrong. A function definition cannot have values.
You need to define the type of the context:
const std = #import("std");
const Context = struct {
};
fn SomeClass() type {
return struct {
fn call(context: Context) u32 {
_ = context;
return 42;
}
};
}
test "doing a thing" {
{
const calc_result = SomeClass().call(.{});
try std.testing.expectEqual(calc_result, 42);
}
}
Or, use anytype:
fn call(context: anytype) u32 { ... }

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.

Calling GMP from Zig

I'm new to Zig and wanted to use the cImport to call out to the GNU Multiprecision library GMP. I got this to work but it feels awkward because Zig apparently doesn't cast from arrays to pointers by default and GMP uses this approach to pass by reference. Is there a cleaner approach than mine? Are there existing examples of Zig calling GMP?
const gmp = #cImport({
#cInclude("gmp.h");
});
pub fn main() void {
var x: gmp.mpz_t = undefined;
gmp.mpz_init(&x[0]);
gmp.mpz_set_ui(&x[0], 7);
gmp.mpz_mul(&x[0], &x[0], &x[0]);
_ = gmp.gmp_printf("%Zd\n", x);
}
You should be able to drop the [0]:
const gmp = #cImport({
#cInclude("gmp.h");
});
pub fn main() void {
var x: gmp.mpz_t = undefined;
gmp.mpz_init(&x);
gmp.mpz_set_ui(&x, 7);
gmp.mpz_mul(&x, &x, &x);
_ = gmp.gmp_printf("%Zd\n", x);
}

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);
}

Rust invalid pointer with Box::from_raw() Box::into_raw() round trip

I'm banging my head against this supposedly simple usage of Box whilst trying to create some FFI helper code.
The sample here seems to give an error of free(): invalid pointer when used with a struct that has a field.
pub struct Handle(usize);
impl Handle {
pub fn from<T>(obj: T) -> Self {
let boxed = Box::new(obj);
let mut ptr = Box::into_raw(boxed);
Self::from_ptr_mut(&mut ptr)
}
pub fn from_ptr_mut<T>(ptr: &mut T) -> Self {
Self(ptr as *mut T as usize)
}
pub fn to_box<T>(self) -> Box<T> {
let obj: *mut T = self.to_ptr_mut();
unsafe { Box::from_raw(obj) }
}
pub fn to_ptr_mut<T>(self) -> *mut T {
self.0 as *mut T
}
}
#[allow(dead_code)]
struct Crashes { value: u64 }
impl Drop for Crashes {
fn drop(&mut self) {
println!("Crashes dropped");
}
}
fn crashes() {
let t = Crashes { value: 12 };
let a = Handle::from(t);
let b = a.to_box::<Crashes>();
drop(b);
}
struct Works;
impl Drop for Works {
fn drop(&mut self) {
println!("Works dropped");
}
}
fn works() {
let t = Works;
let a = Handle::from(t);
let b = a.to_box::<Works>();
drop(b);
}
fn main() {
works();
crashes();
}
You can paste this into https://play.rust-lang.org/ and see how it throws aborts with the error free(): invalid pointer
The drop function seems to be called at the appropriate time, but the pointer seems to be somehow invalid
You end up creating a double pointer here:
impl Handle {
pub fn from<T>(obj: T) -> Self {
let boxed = Box::new(obj);
let mut ptr = Box::into_raw(boxed);
Self::from_ptr_mut(&mut ptr)
}
pub fn from_ptr_mut<T>(ptr: &mut T) -> Self {
Self(ptr as *mut T as usize)
}
...
}
Box::into_raw returns a pointer, but then you take a mutable reference to that pointer, and store that address as a usize. You should just be using the *mut T as returned by Box::into_raw.
The reason that the non-working code with the double pointer compiles is that your from<T> and your from_ptr_mut<T> can take entirely different T parameters. If we consider the type T passed to from<T> to be a concrete type, then in this case you're calling from_ptr_mut<U> (where U is *mut T) with an argument of type &mut *mut T.
It should look like so:
impl Handle {
pub fn from<T>(obj: T) -> Self {
let boxed = Box::new(obj);
let ptr = Box::into_raw(boxed);
Self::from_ptr_mut(ptr)
}
pub fn from_ptr_mut<T>(ptr: *mut T) -> Self {
Self(ptr as usize)
}
...
}
Working example in the playground.
Even though we are in the realm of unsafe you can have the compiler do some of the work for you by making the parameter T be bound to your Handle struct. This way you will be statically prevented from loading a different type than was stored.
Playground example where Handle includes a PhantomData.
In this second example you don't have to tell the compiler which item you're retrieving a la a.to_box::<Crashes>(), which is good because you can't introduce undefined behavior by specifying the wrong type.

Resources