-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
from_candid()
can't decode tuple types?
#4130
Comments
from_candid()
can't decode tuple types?
Weird but true. This works: let blob = to_candid("text", 1);
return from_candid(blob); This too:
And we have tests like that. But this won't work: assert ?("text", 1) == from_candid(to_candid(("text", 1))) : ?((Text, Nat));
assert to_candid(("text", 1)) == to_candid("text", 1);
Eeek,
demonstrates that
There might be a (theoretical) way to pull it out. If we allow interpreting the single-argument Candid-encoding as a record with index 0, then |
One solution might be to make |
Sounds great! So what you suggest is |
|
Almost. What I was suggesting is from_candid<t1,..,tn>(blob) : blob -> ?(t1,...,tn) (i.e. allow some optional type parameters) Now you can specify the arity if needed. So: from_candid<(Int,Nat)> : blob -> ?((Int,Nat),) Not sure it would solve the problems with 1-tuples though which don't even exist in Motoko.... Sigh. Here's a workaround that works by abusing Candid's defaulting option types: public query func decode2() : async ?(text : Text, nat: Nat) {
let data: (Text, Nat) = ("text", 1);
let blob = to_candid(data);
switch (from_candid(blob) : ?((Text,Nat), ?())) {
case null null;
case (?(d, _)) ?d;
}
}; |
Another (perhaps wacky) option that might work would be to have
example:
The length of the argument patterns sequence determines the arity and mirrors the introduction syntax. Not pretty, but we could use constructor |
I think everything is working as expected. I answered the same question on the forum: https://forum.dfinity.org/t/candid-and-tuples/17800/7 |
No I think it's actually a bug, to_candid, which is syntax directed, is doing the right thing, but from_candid, which is only type directed, doesn't have enough info to distinguish between a singleton sequence containing a tuple and a tuple. I think. Using the pattern syntax or type parameters would help. |
Your trick of using a record to force the decoding is neat, but subtle. |
That's due to the semantic gap between Motoko and Candid. |
Given the cost of decoding, may using a pattern is a bad idea, in case people use the pattern in alternative cases etc... |
Only, it doesn't work because the top-level argument sequence is neither a tuple, nor a record in Candid. See test #4138. EDIT: Wow indeed it works: let ?{_0_ = a; _1_ = b; _2_ = c} = from_candid(blob) : ?{_0_:Text; _1_: Nat; _2_: Bool};
?(a, b, c) But OP's code isn't fixable the same way: public query func decode() : async ?(text : Text, nat: Nat) {
let data: (Text, Nat) = ("text", 1);
let blob = to_candid(data);
let ?{_0_ = d} = from_candid(blob) : ?{_0_ : (Text, Nat)};
return ?d;
}; But, this works: public query func decode() : async ?(text : Text, nat: Nat) {
let data: (Text, Nat) = ("text", 1);
let blob = to_candid(data);
let ?{_0_ = d; _1_ = f} = from_candid(blob) : ?{_0_ : Text; _1_ : Nat};
return ?(d, f);
}; I guess the non-tuple type under the option extracts the single arg, and it's components become the components of the tuple that we have put in. I'll write a test case for this if not yet present. |
I just double checked and the trick @chenyan-dfinity describes on the forum does seem to work (he's decoding a single argument sequence containing a triple as first argument to a triple. |
Example:
https://m7sm4-2iaaa-aaaab-qabra-cai.ic0.app/?tag=3732396148
See below a few ways to accomplish what you want!
The text was updated successfully, but these errors were encountered: