-
Notifications
You must be signed in to change notification settings - Fork 694
[sample implementation] simple Abstract Types extension #1394
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
Comments
Thanks for the great write-up, @awendland! Since you mentioned me, I wanted to clarify that I am actually of the opinion that, if WebAssembly were to follow standard practice, such an extension would be unnecessary. Most module systems ensure data abstraction by default. For example, Java/C# modules do not let outsiders access private fields (though modules might provide indirect access through the reflection data it provides, which is controlled by various security settings). That said, OCaml does come to mind as an outlier due to its unsafe However, such standard practice is incompatible with By the way, this proposal seems to be very similar to the |
Nice! As @RossTate points out, this looks similar to the private types in the type import proposal, except that that treats private types as reference types, in order to allow hiding any type, not just i32. However, looking at the patch, I'm not sure I fully follow the type factorisation you use, e.g., how different sealed types are distinguished, especially at module boundaries -- there doesn't seem to be any link between
That's nonsense. All reasonable module systems support both public (alias) and private (abstract) type definitions, so you need to distinguish both forms somehow. Doesn't matter what the default is, though public is more natural given the preexisting Wasm semantics. That's also what other advanced module systems default to if you do not filter exports explicitly, e.g. ML or Haskell.
Sigh. The abstraction mechanism proposed is pretty much how class-based abstraction works in OO languages, how newtype works in Haskell, how abstype works in SML, and so on and so forth. It is the most wide-spread form of value-based type abstraction. None of this has much to do with RTTs either. |
Haskell's So The same applies to SML's
This example shows that it's possible to reinterpret an array with a public type as an array with a private type. In particular, the two values share the same state. This is impossible with any dynamic abstraction mechanism. Yet the ability to seal the type of values without casts is useful because a module can then can be implemented using some library designed for integer arrays but only expose its values as arrays of an abstract type (e.g. to prevent forging). Because SML ensures data abstraction by default, even though these values are not dynamically sealed there is no way for another module to cast them to or from integers.
This response seems to be due to a misunderstanding of what I was describing. Hopefully the above clarifies what I meant. Hopefully now it's clear that standard practice is that values exported via an opaque/sealed type are not dynamically wrapped—instead, the type/module system ensures that values exported via an opaque/sealed type can only be used according to what the various module exports enable. However, that standard practice is incompatible with So we are sacrificing performance and standard guarantees in order to support |
I don't expect this to be particularly useful to anyone, especially with the exciting work going on with the GC proposal and Type Imports proposal, but I wanted to share this abstract types language extension I implemented in case it is relevant to someone.
You can launch a Jupyter notebook with several examples and a modified Wasm interpreter implementing the following features by clicking
.
Overview
I've implemented a small extension to the WebAssembly language that introduces abstract types (also known as "existential types" or "abstract data types" or "opaque references" or "nominal types"). I built this in the context of my undergraduate thesis which explored using WebAssembly as a multi-language platform (by enabling the various features needed for secure compilation).
This implementation of abstract types is based on OCaml's abstract types and loosely conforms with the ideas expressed by @rossberg and @RossTate in WebAssembly/proposal-type-imports#7:
These features allow WebAssembly to enforce higher-level abstractions such as:
a
inlet a = new Date(); a.getYear()
)Usage
To work with these new abstract types, I've introduced 4 operators to the language. The syntax is verbose in order to ensure clarity in the operations being performed. It's likely that a more ergonomic syntax would be adopted, such as merging the
abstype_new
andabstype_sealed
namespaces and referring to them with a single operator, as well as overloading the existingtype
instruction to support abstract types. For now, the syntax is as follows:abstype_new
abstype_new [IDENTIFIER] value_type
abstype_sealed_ref
)abstype_sealed
abstype_sealed [IDENTIFIER]
import
instruction, i.e.(import "mod" "id" (abstype_sealed [IDENTIFIER]))
abstype_new_ref
abstype_new_ref IDENTIFIER
abstype_new
)abstype_sealed_ref
abstype_sealed_ref IDENTIFIER
abstype_sealed
)Abstract types manifest in two ways:
abstype_new*
instructions are used within a given module. These abstract types are "unwrapped" within the module, and are treated as their underlying value_types. In this way, local abstract types are more like type aliases. This allows abstract types to be constructed, and only take on their abstract nature when used in a separate module.abstype_sealed*
instructions are being used. These abstract types are treated as opaque identifiers referencing the source module instance and the export statement. These abstract types are only treated as their underlying values upon program execution (i.e. after validation). Additionally, they do not have default values, so trying to immediately use alocal
with a sealed abstract type will fail, instead, thelocal
must be populated with a value provided by the sealed abstract type's source module.Examples
You can see simple syntax/usage examples in the test file for this feature at test/core/abstract-types.wast.
For something more interesting, I've configured my awendland/2020-thesis repository to be runnable via Binder so that you can jump right into a web-based Jupyter notebook with this
webassembly-spec-abstypes
interpreter already available and the code insamples/
all runnable. Try it out with:Implementation Details
I've created a PR (awendland/webassembly-spec-abstypes#4) showcasing the implementation on top of the reference interpreter's Reference Types Proposal branch.
The core changes for stack type checking were in interpreter/syntax/types.ml:
SealedAbsType of int32
tovalue_type
value_type
calledwrapped_value_types
that could be aNewAbsType of value_type * int32
in addition to a straightvalue_type
.In both of these instances, the
i32
value represents a unique identifier for the abstract type, since the types are "nominal", as in, even if they have the same underlying type they're unique if they are from different definitions (i.e. differentabstype_new
operations). See the test suite where this distinction is demonstrated.The core changes for type checking module linking were implemented in a new module called interpreter/runtime/extern_types.ml that:
All uses of
value_type
(should) have been expanded to support abstract types.Work in Progress
Several aspects of this implementation are unfinished (and likely to remain so given the exciting development going on with the GC Proposal and my interests moving elsewhere). I documented the issues I was aware of in the test suite; they are:
Additionally, I only implemented abstract types for the textual representation of WebAssembly, not the binary variant or the JS API. The binary variant should be a straightforward addition. The JS API will require various decisions to be made around how to enforce the abstraction across the JS boundary; hard problems that are getting compelling answers in the GC Proposal.
Related Discussions
This small language extension is related to much more exciting discussions going on elsewhere, such as:
It's also loosely related to much grander proposals that are in the works: GC, Type Imports, Interface Types.
Thanks for such great work on WebAssembly! I'm excited to see where the language goes.
The text was updated successfully, but these errors were encountered: