Since you are importing the class instance as a canister (not Motoko actor class library) moc doesn’t know it’s a Motoko canister. The candid interface will say add : [vec Nat8] -> () and Foo will have imported type [Nat8] -> async {} after re-translation from Candid to Moc.
The code would work if you imported the actor class directly as a library and communicated with an instance of that class, because Moc then uses the Motoko type of the actor class direclty, not the generated Candid interface.
In Candid, blob is just an abbreviation for vec nat8 (but not in Motoko).
You can convert the data to an array if you don’t mind the expense (Blob.toArray(data)).
Another hacky workaround would be to cast Foo to another actor type that has the blob method. It should work, is gross, but cheaper than the array conversion.
Something like
{
let foo = actor (Principal.toText(Principal.fromActor(Foo))) : actor { add : Blob -> () }
foo.add(data);
}
Will it consume 4x more bytes if I use [Nat8] instead of Blob for inter-canister calls(message size)?
In the message (Candid binary), no, in memory, yes.
Not my case, but if it’s not just a blob argument there, but more complex nested type, shared between canisters, there would be more inconvenience.
yep.
I don’t understand why Motoko doesn’t generate blob, since for Motoko they are two different types.
Well, it does, but Candid blob is just Candid vec nat8. There is no distinct blob type to generate.
Feels like a bug, not a feature to be honest.
Well, bug is a bit strong, but needless minimalism, maybe. Life would be simpler if Candid just had a distinct blob type, I think. I mean, it does for principal, IIRC.