15:26
<shu>
this room also never had an orange TC39 logo for me
15:26
<shu>
dunno how this stuff works
15:31
<asumu>
At 9AM PDT I'll be talking a bit about the connection between Wasm GC & this proposal (among other things) at the Wasm GC subgroup: https://github.com/WebAssembly/gc/issues/237
17:00
<shu>
sorry i missed this, i don't have the GC subgroup meetings on my calendar, though always happy to attend fewer meetings
17:00
<shu>
how did it go, asumu?
17:09
<asumu>
I think it went well! There was a lot of agreement overall. One of the bigger points of discussion was what can be done about type-checking in the JS->Wasm direction. There was some discussion on how that might be possible by extending Wasm's API, perhaps even without adding more types to the JS structs proposal (which of course we had agreed wasn't part of the initial proposal).
17:10
<asumu>
Slides here: https://docs.google.com/presentation/d/1XwCwOQvTTuV5mU74d2wLnEqsdpi20ReCxtFRZLcW0EA/edit?usp=sharing
19:36
<shu>
cool, thanks for the slides
19:37
<shu>
makes me think i should attend the GC subgroup meetings, if only mostly as an observer
19:38
<rbuckton>
One thing that Shu and I were discussing was the possibility of using decorators to handle marshaling behavior for things like FFIs. I'm still interested in RTT support and how to align that with TypeScript
19:47
<rbuckton>

In the proposal draft I was working on, I used : type (similar to TypeScript) for a restricted subset of types, with the possibility of using something like TS generics for specific subtyping (i.e., kind: i32<Kind>, where the <Kind> would be erased by TS on emit). Another approach was a prefix (type) similar to what I was thinking for operator overloading:

struct Point {
  (i32) x;
  (i32) y;
  static (Point + i32) (a, b) { return new Point(a.x + b, a.y + b); }
  ...
}

But this could also theoretically be handled by decorators under the current proposal:

struct class Point {
  @WebAssembly.Type("i32") x;
  @WebAssembly.Type("i32") y;
}
// or
const { i32 } = WebAssembly.Types;
struct class Point {
  @i32 x;
  @i32 y;
}
20:57
<shu>
using decorators makes sense if types (really, "size + representation" instead of "type" writ large) were always applied via API like a WebAssembly API
20:58
<shu>
but i think a desire exists to declare size+representation for JS structs for use within JS as well, and how would that work?
20:58
<shu>
and to be clear, i think a world where the size+repr are only the purview of WebAssembly is actually fine
20:59
<shu>
but that might ruffle some feathers for platforms that don't want to include wasm but do want sized fields
23:00
<rbuckton>

The @type decorator approach wouldn't be the first time we've seen a similar proposal. I think littledan considered something for user-defined numeric literal suffixes as well (i.e., 123@px).

Also, it wouldn't necessarily need to be tied to WebAssembly if we went with that approach. There are a few use cases it doesn't solve though (like fixed size arrays, etc.) that I was considering here: https://github.com/rbuckton/proposal-struct#field-types

23:17
<rbuckton>

Specific cases being something like:

  1. i32[8] for a fixed-size array of 8 32-bit signed integers (derived from standard C/C++ array field declarators and C# array field declarators)
  2. i32[length] for a dependent-sized array whose size is derived from another field on the object (roughly based on https://docs.microsoft.com/en-us/windows/win32/midl/midl-arrays, though possibly not feasible if length is mutable).
  3. i32[] for a flexible-sized array (based on C99 flexible array members https://en.wikipedia.org/wiki/Flexible_array_member)
23:20
<shu>
you think those can be done with decorators instead of building them in?
23:20
<rbuckton>
(2) may be unlikely. In most cases where I've seen a similar construct it has been purely informative and primarily intended for describing marshaling.
23:20
<shu>
or should be done with decorators?
23:20
<rbuckton>
I think either are feasible, though building in syntax might be preferred.
23:20
<shu>
(3) is enshrining a common pattern in the kind of programming i do, i'd be happy with that
23:28
<rbuckton>

Decorators do provide some flexibility, and we could leverage MetaProperty, i.e.:

struct class Foo {
  @struct.type(struct.i32)
  x;
  @struct.type(struct.i32, { size: 8 })
  y;
  @struct.type(struct.i32, { size: "flexible" })
  z;
}

You would run into the same issue decorators has with circular references though:

struct class A {
  @struct.type(struct.i32)
  size;
  @struct.type(B, { size: "flexible" })
  bArray;
}
struct class B {
  @struct.type(struct.i32)
  size;
  @struct.type(A, { size: "flexible" })
  aArray;
}

That was one of the other motivators for ref:

struct class A {
  @struct.type(struct.i32)
  size;
  @struct.type(ref B, { size: "flexible" }) // reference `B`
  bArray;
}
struct class B {
  @struct.type(struct.i32)
  size;
  @struct.type(A, { size: "flexible" })
  aArray;
}
23:29
<rbuckton>
Downsides of MetaProperty are the repetition and the fact you can't destructure.
23:29
<shu>
sorry, would like to engage more fully here but am busy today. are you mainly interested in discussing the syntax space for a unified future-proof mechanism for both types and arrays?
23:30
<shu>
(more top of mind for me is whether we should pull arrays into scope)
23:30
<rbuckton>
I'm interested in that among other things, yes.
23:31
<rbuckton>
Arrays are definitely useful, otherwise your only option for shared lists will be linked lists
23:34
<rbuckton>
Of course, struct isn't a reserved word, so it wouldn't be a MetaProperty anyways...
23:37
<rbuckton>
If types are defined via decorators we'd need some place to put them. That same place would be as good as any other for defining possible marshalling behavior for other things as well (like pseudo-blittable representations, struct layout and packing behavior, marshalling strings and arrays, FFI interop mechanisms, etc.)
23:39
<rbuckton>

Maybe a global Interop object (since anything non-Proxy related can't go on Reflect). Then you could write:

const { type, i32 } = Interop;
struct class Foo {
  @type(i32) x;
  @type(i32) y;
}

But there's plenty to bikeshed there.