-
Notifications
You must be signed in to change notification settings - Fork 20
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
Module references #12
Comments
This looks like it will be an incredibly useful feature for Dex's. I have some comments and general questions surrounding the implementation of something like this. Syntax
Questions
|
|
@emilypi Wanted to record here our discussion about the isomorphism with row types, which rationalizes borrowing the syntax from user schema types. For purposes of this discussion I'll go with We can generally extend the Likewise, for module references, The isomorphism is fascinating to me, as I've never considered "row types for module signatures" and in general have only heard of row types applying to "plain old" datatypes. But I suppose an interface can be seen as a constructor taking function types. I guess the only thing I might throw into this discussion is "what about type variables"? For instance Haskell allows for composition of typeclass constraints by accumulating constraints on a type variable, as opposed to a
At the usage site, how is
I would (perhaps prematurely) conclude that schema type variables will not feature constraints and instead will be universal vs specialized in this fashion. This seems to motivate the "row type" presentation. The one thing I was noticing about row type presentation vs Haskell constraints on a type variable is you get a little bit of reuse within a signature:
There's no "shorthand" for the |
Problem Statement
Pact lacks a mechanism for polymorphic dynamic dispatch: all dispatch in Pact is resolved at compile/install time, and polymorphic dispatch is not offered at all. While this is not a significant limitation for many smart contract applications, and indeed "static linking" has safety benefits, certain kinds of apps need to interact with other applications dynamically.
Consider a Uniswap-style exchange that interacts with
fungible-v2
tokens. On the EVM, Uniswap offers the ability to add new pairs on-demand, as a business-critical feature. In Pact, dynamic interaction with other contracts is not possible.A work-around could employ a mechanism, such as a "fungible registry" that would provide indirection along the lines of dispatching on token symbol to
fungible-v2
methods liketransfer
. A new token would simply require a modification referencing the new token's code and an update to the code on the blockchain. Such a registry could service any number of applications seeking to access fungible tokens.Nonetheless, in addition to updating the registry, the client software, in this example the exchange, would have to be re-uploaded simply to link to the new registry version. This is because Pact intentionally does not automatically upgrade downstream dependencies, as an safety feature for code stability and resilience.
However, the registry code itself would reveal another problem: the lack of a polymorphic dispatch mechanism. The registry would have to manually case on symbol for each operation, resulting in massive duplicative calls to
transfer
and other methods. Code proliferates with the potential for bugs.A solution must allow for dynamic dispatch to a module, and polymorphic access to the methods of implemented interfaces.
Proposal Draft: Module References
Module references reify a Pact module into a concrete datatype. For purposes of this draft we will say it's type is
ref
, but it might benefit from a different name. Here is a function signature that accepts a module ref:ref
by itself is not very useful as it gives no indication what interface the module implements. A simple re-purposing of Pact's user-schema type syntax could indicate a single supported interface:If refs were to support multiple interfaces, this syntax would be insufficient. However an argument can be made for only supporting single interfaces to make roles clear. Consider an ancilliary interface to
fungible-v2
that specifies whitelisting, a signature would expect two arguments:Usage
The simplest way to use a module ref is for it to "stand in" for standard Pact unqualified namespace syntax:
This of course will complicate resolution. Presumably reference arguments would shadow unqualified namespaces.
Instantiation
The most straightforward way to provide a module reference would be to reference the module itself as a bareword:
In the case of a module that implements two interfaces, it would just be used twice:
At least in the root namespace, this would cause name clashes with existing Pact code which is free to reuse module names. For instance the coin contract can use a variable called
coin
with no ambiguity.This also impacts resolution as it would introduce
[namespace.]module
references in Pact code as concrete datatypes. An alternate approach would be to explicitly declare module references, with perhaps adefref
form:Or, an
implements
declaration could be extended to declare the ref:The advantage of this is simply to provide a context for resolution, as opposed to special syntactic support for recognizing module refs. It also avoids the name clash issues.
Additional requirements
A module reference MUST be storable in the database, in order for something like
add-fungible
to work as intended.Further considerations
Safety. Pact's existing system of static linking provides strong guarantees:
The text was updated successfully, but these errors were encountered: