tc39 / proposal-structs

JavaScript Structs: Fixed Layout Objects
http://tc39.es/proposal-structs/
622 stars 11 forks source link

Potential for more minimalism #13

Closed annevk closed 1 month ago

annevk commented 3 years ago

I'm still curious about https://twitter.com/annevk/status/1433688193321291778. It seems to me that shared structs (or at least the additional restrictions they add) would be a strictly simpler starting point than having both shared and non-shared structs.

And when I look at the motivation I only see compelling cases for shared structs.

syg commented 3 years ago

I had forgotten about this, thanks for the reminder.

The even more restrictive but simpler version is indeed a valid alternative starting point. I'm not yet completely sold but certainly appreciate the simplicity; see some of my thoughts in https://github.com/syg/proposal-structs/issues/14#issuecomment-953184027

How do the other champions @rbuckton and @takikawa feel?

ljharb commented 3 years ago

It seems very strange to me to add something as heavy as syntax for something whose only use case is SAB/Atomics.

MaxGraey commented 3 years ago

I proposed light syntax here: https://github.com/syg/proposal-structs/issues/1. But my suggestion did not provoke any positive response at the time

syg commented 3 years ago

It's explicitly not based on SAB/Atomics. I suppose you mean shared memory in general?

I agree that it's possible to do structured data without syntax, but also what's proposed here is a single contextual keyword, which I'd argue is about as lightweight as syntax goes.

Also, this issue isn't about syntax but about more minimal semantics. Please start a new issue if you'd like to discuss syntax.

Edit: By not based on I mean these things aren't exposed via SABs.

syg commented 3 years ago

whose only use case is SAB/Atomics

This isn't an accurate characterization. Folks have said they don't find the non-shared struct use cases as compelling, but there are obviously use cases for fixed layout objects that doesn't involve sharing, like non-shared memory WasmGC. I'm not sure where the disconnect is coming from. If it's stemming from a feeling that Wasm shoudn't affect JS, I strongly contend that we as JS folks can't put our heads in the sand about Wasm at the boundary.

ljharb commented 3 years ago

@syg i wasn't speaking about the relative weight of the syntax itself, just about the fact that it's syntax alone, for only yes, shared memory in general.

I completely understand that there's non-shared use cases - I have lots of use for simple immutable structures, including Records, Tuples, and these - but maybe I'm misunderstanding the topic of this thread. It seems like a suggestion to reduce the proposal so you couldn't use structs except for sharing use cases?

syg commented 3 years ago

I completely understand that there's non-shared use cases - I have lots of use for simple immutable structures, including Records, Tuples, and these - but maybe I'm misunderstanding the topic of this thread. It seems like a suggestion to reduce the proposal so you couldn't use structs except for sharing use cases?

These aren't immutable. These are mutable and have identity. Their layouts are immutable, but their data certainly aren't immutable.

I'm still confused by the connection to syntax. Reducing the scope to shared only doesn't imply removing syntax to me. Syntax would be just as important for the shared use case. Something declarative is much better here for intent, ergonomics, and implementation.

ljharb commented 3 years ago

Thanks for clarifying. Fixed shape mutable objects are also something I have a use case for :-)

Maybe the part I'm not understanding is what "only provide shared structs" means. Would I be able to use a shared struct, without shared memory, and it would act as if it was non-shared? Or is there a difference I'm missing?

syg commented 3 years ago

Maybe the part I'm not understanding is what "only provide shared structs" means. Would I be able to use a shared struct, without shared memory, and it would act as if it was non-shared? Or is there a difference I'm missing?

Ah I see. I'm not sure what @annevk had in mind, but what I had in mind is exactly as you say. You can use shared structs, even in a non-shared setting, as you can per the proposal today. This is suboptimal because shared structs have additional restrictions that don't need to be there for the non-shared use case.

I think the two main problematic restrictions for using shared structs as non-shared structs are:

  1. Shared struct fields can only reference primitives and shared structs. This is to make sharing explicitly opt-in as it is today with SABs. If a shared struct s could point to a local plain object o, sharing s would make o shared, which isn't possible to do.

  2. Shared structs will have lower performance than non-shared structs, because their implementation have to support concurrent access. This will mean, at the very least, that field accesses will use atomic instructions on the underlying CPU, which are slower than non-atomic instructions.

ljharb commented 3 years ago

The second point doesn't concern me much; if usage is high enough in scenarios where there's no concurrent access, it seems like potentially implementations could optimize for that?

The first one, however, does seem like an issue for non-shared use cases, and also seems to overlap with the issues Records and Tuples are struggling with around Box.

syg commented 3 years ago

The second point doesn't concern me much; if usage is high enough in scenarios where there's no concurrent access, it seems like potentially implementations could optimize for that?

Maybe, but unfortunately I don't think very easily. You'd end up needing to track a "have shared structs of this shape actually been shared across threads" bit and then invalidate a bunch of optimized code and IC handlers. Possible, sure, but that kind of performance cliff seems antithetical to the goal of fixed layout objects, which should be getting us more predictable performance.

annevk commented 3 years ago

I think there's two things I'd like to see clarified:

For the latter, one thing I was thinking of is that it seems like a nice property that you could always serialize a struct, which isn't really possible if it can point to a function or some such.

takikawa commented 3 years ago

I think the two main problematic restrictions for using shared structs as non-shared structs are: [...] Shared structs will have lower performance than non-shared structs, because their implementation have to support concurrent access.

I think that this will be a big deal for the Wasm GC use case, in that better performance is a key motivation for wanting to compile to Wasm. If Wasm GC's JS API design forces lower performance when interacting with JS due to using shared structs, I don't think Wasm engine implementers would be happy with the design (nor the Wasm producers who are compiling to it).

(I do think concurrency will be important for Wasm GC structs in the future as well, but this will likely be in a while after the implementation of the existing non-concurrent GC is further along)

syg commented 1 month ago

Closing some old threads.

This proposal currently plans to go forward with both non-shared and shared structs. The use cases for non-shared structs are: