-
Notifications
You must be signed in to change notification settings - Fork 688
[move-stdlib] add struct decomposition via new struct_tag
module
#971
base: main
Are you sure you want to change the base?
Conversation
struct_tag
module
Note that for struct_tag.address_, we could also go with other names, like 'addr', 'package', or 'account'. Aptos and Sui both have different naming conventions (Aptos calls them account-addresses whereas Sui calls them package-ids), and we wanted to be inclusive of both. Additionally for generics, we went with |
} | ||
|
||
/// Returns the module authority for the struct of type `T` | ||
public fun module_authority<T>(): StructTag { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to understand the module authority? I see the struct_name is hardcode Witness
, so is it a programming pattern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah exactly! My intention is that every module should be able to assert their ownership in this way. For example you could do something like:
public fun do_something<T: drop>(witness: T, object: &Object) {
assert!(struct_tag::module_authority<Object> == struct_tag::get<T>, ENO_MODULE_AUTHORITY);
...
This is stating that, in order for this function to continue, we need a witness, and that Witness must be the module-authority witness produced by the same module that produced the Object.
This way we can guarantee that this function-call originated from the same module that defined Object in the first place. So even if you obtain a reference to &Object, you won't be able to use it without the defining-module's permission (from a Witness).
We've been using this pattern to authorize getting a mutable reference to an object from a type-erased container which should only be allowed in the context of the module defining said object. This PR would be very helpful to achieve that. Here is a link to our documentation which should put it in context: |
Apologies for being slow in replying to this. I left some comments that I'll reproduce here for convenience
@PaulFidika replied to the third point with some specific use-cases that make a lot of sense to support, but I think we can do so with a reflection API that is slightly less powerful, or at least uses the big hammer of converting types into strings only when it's needed. Keeping the artifacts we reflect over as opaque as possible will make life easier for static reasoning tools like the Prover--when we go into string-land, things get a lot trickier for such tools. The two use-cases Paul suggested (also in the thread above) are:
What do you think about adding functions specifically for these generic/helpful use-cases (e.g., |
Motivation
This adds introspection decomposition of struct-types into Move natively.
While working with Move, we've found the need to pull out pieces of a struct's type (such as the package-id / account-address of where the declaring module is published); we've built such solutions using std::type_name, but this is involves parsing ascii strings, which is costly (from a gas perspective).
To make this process easier, we're introducing a new native module called struct_tag, which creates a StructTag type, which has all of the components of a struct's type (package-id, module-name, struct-name, and generics) already broken down into easy-to-use pieces.
For primitive types, such as vector, attempting to get a StructTag will abort, because primitive types do not have the same structure as struct-types. We thought this solution was better than creating a struct-tag with most of its fields empty. We're open to revise this decision however.
Also, for more information about this please see #966
Have you read the Contributing Guidelines on pull requests?
Yes
Test Plan
after switching current dir to
move/language/move-stdlib
, runcargo run -p df-cli -- test