Gc: Clarification on i31ref nullability

Created on 25 Aug 2020  路  7Comments  路  Source: WebAssembly/gc

In the MVP document, under reference types, the following is noted:

  • anyref is a new reference type

    • anyref == (ref null any)

  • eqref is a new reference type

    • eqref == (ref null eq)

  • i31ref is a new reference type

    • i31ref == (ref i31)

with i31ref equalling (ref i31) not (ref null i31). This turned up during prototyping in Binaryen where the initial strategy was to default to the abbreviations, but with (ref i31) != (ref null i31), and with (ref null i31) theoretically constructible, we'd then be missing a canonical name for (ref null i31). This is not a problem, as we can design this differently by defaulting to the heaptype representation with the abbreviations merely being aliases, but I'd like to know more about the design here, as it might also be that this is either an oversight or that it hints at (ref null i31) being illegal?

All 7 comments

I had a similar question when I implemented i31ref in V8, and the impression I got was that i31ref == (ref i31) was intentional, and hints at (ref null i31) being presumed less useful (though legal).

(Side note: it seems we went through a very similar journey as you did: in our internal representation, our ValueType evolved from an enum to a class wrapping a separate HeapType, and when we have a need to emit text (or binary test cases), we prefer the shorthands when applicable (e.g. internal (optref eq) is emitted as "eqref".)

Thanks Jakob, going with V8's approach now! Closing as this is answered, but if anyone has differing design insights, please let me know :)

What @jakobkummerow said. Having a different nullability default for the i31ref shorthand was a pragmatic choice based on expected use cases, but it is a bit irregular. We can switch it around if folks think that's preferable. Opinions?

Having a different nullability default for the i31ref shorthand was a pragmatic choice based on expected use cases, but it is a bit irregular. We can switch it around if folks think that's preferable. Opinions?

So far I found that the irregularity requires frequent special casing of i31ref where all the other canonical refs have something in common, i.e. possibly null. Another challenge is, when creating globals using an enum of all the canonical types, all these types currently have a trivial initializer except i31ref (unless i31.new is meant to become a valid constant initializer expression, or introducing i31.zero). This is mostly a matter of convenience for implementers, though, and if more canonical names for non-nullable types are introduced it'd instantly feel less alien I guess.

What about #130 ?

Hmm, I don't really get the point in #130 ((ref i31 func) or even a concrete struct?), but I also already didn't get why i31ref has been introduced in the first place given the complexity it imposes on the type system for very little gain. Hence I might mistakenly see the suggestion there as just another continuation of a mistake. In general I am only confident about anyref, func, struct and array, and all the other curiosities seem odd to me, especially in an MVP.

The point of #130 is to treat tagged integers as orthogonal dimension in the type system the way nullability is.

I think it's easier to separate i31ref from the GC proposal if it is this orthogonal dimension.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vargaz picture vargaz  路  8Comments

RossTate picture RossTate  路  7Comments

dcodeIO picture dcodeIO  路  17Comments

binji picture binji  路  16Comments

TomMarius picture TomMarius  路  3Comments