zeek/spicy

`inout` unit parameter does not work with unit variable

Closed this issue · 3 comments

I was trying to adapt the example for using inout parameters with basic types from the docs to use a unit variable instead of a global:

module Test;

type X = unit(inout msg: string&) {
    n : uint8 {
      local s = "Parsed %d" % $$;
      msg = new s;
    }
};

public type Y = unit {
    var msg: string& = new "Nothing parsed, yet";

    x: X(self.msg);
    on %done { print self.msg; }
};

Unfortunately, this just prints "Nothing parsed, yet". @bbannier took a look and found:

This seems to be a bug, and even if you printed msg after assigning to it in n’s hook its value would still be unchanged.
Looking in the generated code this seems to be due to Spicy generating a hook-local temporary which is assigned to, but never used.

    ::hilti::rt::StrongReference<std::string> __lhs_1;
    ::hilti::rt::detail::checkStack();
    std::string s = ::hilti::rt::fmt(std::string("Parsed %d"), __dd);
    (__lhs_1=(__self->__p_foo.derefAsValue())) = ::hilti::rt::reference::make_strong<std::string>(s);

Why the reference on string? Is that on purpose or to try work around something not working?

Should this instead be:

type X = unit(inout msg: string) {
    n : uint8 {
      msg = "Parsed %d" % $$;
    }
};

public type Y = unit {
    var msg: string = "Nothing parsed, yet";
...
}

That however is neither working, prints an empty string.

Why the reference on string? Is that on purpose or to try work around something not working?

The docs state "In order to pass a basic type as unit parameter it needs to be declared as a reference (e.g., string&) and explicitly wrapped when being set" and reference #674. Just followed the link and this seems to be fixed for quite some time now.

With #1712, the recommended way now will be:

type X = unit(msg: string&) {
    n : uint8 {
      local s = "Parsed %d" % $$;
      *msg = s;
    }
};

The PR contains some new documentation to explain this.