Open leighmcculloch opened 2 years ago
For a bit of background, the compiler does something along these lines for the Number wrappers already, i.e. I8, I16, I32 etc. are attached to the basic types i8
, i16
, i32
etc. This works because TypeScript tooling can be informed that all these types are basically aliases of number
, and there is the Number
class attached to these in JS that can be mimicked. As such these wrappers are limited to the functionality provided by Number
in JS. This same mechanism would, however, not work with custom methods, since TS tooling would not recognize these. The tricky part hence is to implement this in a TS-compatible way. Open to ideas :)
I think we could take advantage of the fact that TS supports extending primitive types like Number
.
Consider the following example. Val
can be created with any number
value. Once it is created, the underlying number value being stored within is immutable. In TS this is assumedly an object stored on the heap, but it doesn't really matter in contexts where the TS is being run such as a browser. Functionally it is still immutable.
In the AS context, AS could optimize this type definition. It could identify that this class extends a primitive type, and has no other fields. Therefore, it can be treated as an on the stack i32/i64/f32/f64. Ideally it would be possible for the definition to be class Val extends u64
rather than Number
, but I'm a bit fuzzy on if that is possible. Maybe it would need to be class Val extends U64
?
class Val extends Number {
isX(): boolean {
return this.valueOf() == 1;
}
}
let n1 = new Val(1);
let n2 = new Val(2);
console.log(n1.valueOf(), n1.isX())
console.log(n2.valueOf(), n2.isX())
console.log(n1.valueOf(), n1.isX())
console.log(n2.valueOf(), n2.isX())
Ref: TS Playground
Something that would be useful for some applications of wasm modules is to be able to define types that are mapped to primitive wasm types. This is useful in cases where a functions input value is a u64 handle to something on the host side. This is also useful in cases when it is desirable to avoid use of the heap/linear-memory. The user defined type would have an underlying type of that primitive value on the stack, but it could have functions attached to it. From the wasm runtimes POV the type would just be a i64/i32.
This is possible today in Go and Rust that builds to wasm:
AssemblyScript already defines new types and makes them to wasm types, since it makes u64 to i64, and u32 to i32. This would be extending that capability to the user being able to define types that make to a primitive type.
To some degree this is already possible since TypeScript (and AssemblyScript) support type aliases. With type aliases we can say the following, which means
Val
is au64
.However, using a type alias it is not possible to attach functions to the
Val
type, and there is no type safety, because it is truly just an alias and not a new type. Any u64 can be set on a variable of type Val without an explicit cast.