#How can I capture external variables and use closure functions?

1 messages · Page 1 of 1 (latest)

lime wing
#
 while (try iter.next()) |entity| {
            const t = struct {
                fn callback(item: []const u8) bool { 
                    return strings.contains(item, entity.path);
                }
            };

            if (self.option.ignore_dirs != null and strings.some(self.option.ignore_dirs.?, t.callback)) {
                continue;
            }

            if (entity.kind == .file) {
                std.debug.print("entity file = {s}\n", .{entity.path});
            } else {
                std.debug.print("entity dir = {s}\n", .{entity.path});
            }
        }
dapper walrus
#

there are no closures in zig, you have to model them explicitly yourself. for example by using structs with the data and a function that also takes self

lime wing
dapper walrus
#

sorry not right now, its 3am here soon and I'm going to sleep

lime wing
dapper walrus
#

no problem at all, I'll post a quick example tomorrow if I haven't forgotten it by then

#

actually whatever this is what I was thinking of ```rust
const Callback = struct {
my_data: Whatever,
another_field: Foo,

pub fn call(self: Self, normal_args: ...) ... { ... }

}

#

which also means this has to be supported by the interface that accepts the callback, if it expects a simple function pointer without any extra state you can't have any extra state (other than using global state of course)

#

another option is for the function to take separate callback and context arguments, where the context is then also passed to the callback. you can find both variants in std.sort

empty osprey
#

What people usually do to emulate stack capturing macros is


fn calling_fun(callback: anytype) void {
  callback.call(...);
}

calling_fun((struct{

  x: T,

  pub fn call(self: @This) V {
    ...
  }
}){.x = local})

#

Or at least that's what I've seen

#

What you want to capture, you put inside the struct as member variables

undone birch
#

real examples of this pattern are std.sort.*Context functions

plush comet
#

This creates a circular dependency problem for me.
Given

const ItemManagerInterface = struct {
   interact: *fn(mgr: *T) void,
};

pub const Item = struct {
// ...

  pub fn do_something(self: *Item, iface: *ItemManagerInterface) void {
    iface.interact();
  }
};

pub const ItemManager = struct {
  iface: ItemManagerInterface,
  items: std:ArrayList(*Item),
// ...

   pub fn init() ItemManager {
        var ret = .{
           .iface = {
               // ... what should be here?
           },
           .items = std.ArrayList(*Item).init(gpa),
          }
        return ret;
  }
  pub fn update(self: *ItemManager) void {
      for (self.items.items) |itm| {
         itm.do_something(&self.iface);
      }
  }
  pub fn interact(self: *T) {
  /// ...
  }
};
undone birch
#

Note: it's *const fn, not *fn. The latter would only work at comptime, if at all

plush comet
#

maybe. But key problem is chicken-egg.
Item have to declare pointer to ItemManger and vice versa.

undone birch
#

I don't actually see what the issue is, you've omitted too much code and provided no error message

plush comet
#

There is an Item which depends on ItemManagerInterface but ItemManagerInterface is unable to reference ItemManager because it is not declared yet

#

in C this could be resolved with forward declaration struct ItemManager; how to do it in zig?

undone birch
#

not sure what you mean, you can reference it

#

at namespace level, declarations are order-independent

#

you just can't value value-recursive types

plush comet
#

but they could be in different files because there are many sort of Items which packed into tagged union

undone birch
#

okay? they can still reference each other

#

please open a thread with your specific problem, alongside what you're actually trying to do

plush comet
#

Just closure would be one of ways but ok