00:00
<rbuckton>
* This makes it hard for multiple packages to share a common shared struct definition without that common definition also enshrining the key as an exported `const` or some such.
00:04
<rbuckton>
App developers don't like to copy paste protocol definitions, they like to reuse them (see protobuf and other packages). This design adds completely that is likely to result in someone in the ecosystem wrapping it with something easier to use that promotes reuse.
00:07
<Mathieu Hofman>
maybe, but I'm opposed to a shared registry keyed on forgeable values, even just at "init". That approach also doesn't solve the use case of structs defined after init.
00:26
<littledan>
oh creating an empty proto is an interesting alternative i hadn't thought about before
I actually wasn’t suggesting this myself but it is an interesting idea!
00:34
<Mathieu Hofman>
Should there be a constructor on that created "empty" proto ?
00:36
<Mathieu Hofman>
I think there should
00:36
<littledan>
I think not? Others can set that later. But this is bike shedding and not fundamental
00:36
<Mathieu Hofman>
The main issue as ron pointed out is the ergonomic of access to proto methods that haven't been defined
00:37
<Mathieu Hofman>
Without an initial constructor property on this proto, I don't know how you could construct an instance of that struct in the receiver realm
00:39
<littledan>
Oh I see what you mean
00:41
<littledan>
But… maybe this is a separate capability from being able to handle instances
00:44
<rbuckton>
Should there be a constructor on that created "empty" proto ?
No, it might lead someone to think they can use it to construct an instance, but it wouldn't have the necessary construction logic that the original struct had.
00:46
<littledan>
We could make a “clone” method on the prototype instead :)
00:46
<littledan>
This would not imply the same
00:46
<rbuckton>
Without an initial constructor property on this proto, I don't know how you could construct an instance of that struct in the receiver realm
I would say that you shouldn't be able to. If the original definition had validation logic for its inputs, the synthetic constructor would not.
00:48
<littledan>
Anyway I think this new idea which we somehow collectively came up with—to make an empty prototype in each agent which is magically nominally tracked by the engine—is a natural MVP, on top of which most other things are ergonomics (or capabilities like construction, or transmitting appropriate metadata to the other side to be able to select the right methods)
00:48
<littledan>
This is a basis on top of which JS code can implement Ron’s registry
00:48
<Mathieu Hofman>
No, it might lead someone to think they can use it to construct an instance, but it wouldn't have the necessary construction logic that the original struct had.
What do you mean it wouldn't have the construction logic? Why can't it create an instance?
00:49
<littledan>
What do you mean it wouldn't have the construction logic? Why can't it create an instance?
The constructor might do something other than just set the fields in order
00:49
<rbuckton>
We could make a “clone” method on the prototype instead :)
I'd like for shared structs to someday have private state, but I don't see that working well with a synthetic constructor either.
00:49
<littledan>
The main issue as ron pointed out is the ergonomic of access to proto methods that haven't been defined
Sorry what issue is this?
00:50
<Mathieu Hofman>
Constructor behavior would be added on top of a base construct of the instance, which literally just does a construct
00:50
<littledan>
I'd like for shared structs to someday have private state, but I don't see that working well with a synthetic constructor either.
Yeah I would like that too, but there are so many problems…
00:50
<rbuckton>
Sorry what issue is this?
Providing a useful error if you try to access a method on a foreign struct value that has no associated behavior.
00:51
<littledan>
Providing a useful error if you try to access a method on a foreign struct value that has no associated behavior.
Oh, I think that would work out well. You would do strct.method() and the system would say, undefined is not a function. What is the problem?
00:51
<Mathieu Hofman>
too obscure
00:51
<littledan>
Constructor behavior would be added on top of a base construct of the instance, which literally just does a construct
That behavior makes sense but we should maybe call it something other than constructor
00:52
<rbuckton>
Oh, I think that would work out well. You would do strct.method() and the system would say, undefined is not a function. What is the problem?
The setup for sharing behavior is complicated, so a better error would help to diagnose issues
00:52
<littledan>
Maybe it will be possible for the engine to notice that this case is happening and say so with a better message (with no change in actual semantics)
00:53
<rbuckton>
Constructor behavior would be added on top of a base construct of the instance, which literally just does a construct
For the origin trial, maybe, but I don't know if that's how we want it to work by the time we hit Stage 2 and have syntax
00:55
<rbuckton>
That's actually definitely not the way I want it to work by Stage 2
00:58
<Mathieu Hofman>
Ok but whatever syntactic sugar you put on top for the constructor, at the end of the day, it constructs an instance of your shared struct (not of Object), and then runs the constructor behavior with that object as this. The constructor that would show up as the default would simply be an explicit way to construct the base instance.
00:59
<Mathieu Hofman>
You can replace the constructor on the prototype with a behavior enhanced constructor you define that captured the base constructor
01:00
<Mathieu Hofman>
We need to keep in mind this is an advanced feature, and I personally don't think we need the ergonomics to be that polished
01:03
<rbuckton>
I understand the mechanics of what you're describing. I'm saying that I'm opposed to that. Lets say I want to define a shared struct called Range, and in the constructor I want to ensure that start is equal to or less than end. I can either validate or swap the arguments in the user-defined constructor to create the struct in a normalized representation. However, the worker thread could just do new someRange.constructor(10, 0) and wouldn't get that normalization.
01:05
<rbuckton>
That's even more important if we are able to have private state in a struct, where inputs and accesses are guarded. I wouldn't want someone to do new someForeignValue.constructor(incorrectState) and return it to the main thread which would assume it is a correct value.
01:06
<rbuckton>
That becomes a potential attack vector, whereas if construction is unavailable you could pass a shared struct through untrusted code (with no associated behavior) and back into trusted code
01:08
<Mathieu Hofman>
I honestly don't see how you can prevent that in the face of arbitrary registration of behavior for existing struct. Your only control is to register the correct behavior at init. Whether you do that through your registry, or by grabbing and overriding the original constructor, it's the same thing.
01:09
<rbuckton>
If preload/init is isolated from the regular worker script, you can chose what you want to associate and what you don't want to associate. The regular worker script then wouldn't be able to construct things it shouldn't.
01:09
<Mathieu Hofman>
of course the prototype showing up at unexpected times is the problem, and one also solved by my explicit type handle suggestion
01:10
<rbuckton>
If construction is on by default, to prevent it I have to do so during preload, which is a fail-open approach.
01:11
<Mathieu Hofman>
yes I agree that fail open is problematic, and I would much prefer an explicit registration, but that is definitely more complicated than an implicit prototype being created. And in that approach, how would you be able to get a constructor ?
01:14
<rbuckton>
How is that more complicated than an implicit prototype? The only reason we are discussing an implicit prototype is to do the even more complicated thing to patch unregistered struct types.
01:14
<Mathieu Hofman>
the API for explicit registration is more complicated
01:15
<Mathieu Hofman>
especially since I'm opposed to registration based on strings
01:15
<rbuckton>

That said, if we have syntax and decorators, we could potentially make that configurable, i.e.:

@Atomics.Struct({ id: "796eb01e-70d2-42c6-a30f-8bdce572db3d", createable: true })
export shared struct Point {
  x;
  y;
}
01:16
<rbuckton>
especially since I'm opposed to registration based on strings
To clarify: my understanding was that you're opposed to registration based on strings associated with the declaration? The handles approach still uses string based registration.
01:19
<rbuckton>
I keep coming back to the registration-at-declaration approach because its fairly common in many languages. If its at declaration time, wouldn't forgeability be potentially less of an issue since its "first in wins" and we would throw on a duplicate registration so its more than likely your app would fail to start up?
02:54
<Mathieu Hofman>
To clarify: my understanding was that you're opposed to registration based on strings associated with the declaration? The handles approach still uses string based registration.
In the registration mechanism provided by the spec, yes I'm opposed to string based registration. The handle based approach does not offer a string based mechanism at the spec level.
02:57
<Mathieu Hofman>
I keep coming back to the registration-at-declaration approach because its fairly common in many languages. If its at declaration time, wouldn't forgeability be potentially less of an issue since its "first in wins" and we would throw on a duplicate registration so its more than likely your app would fail to start up?
I don't see how registration time changes anything. A first win registration based on forgeable keys provides a global communication channel that is simply unacceptable.
04:17
<Jack Works>
👀
04:17
<Jack Works>
any brief introduction about the recent progress? I have heard it has been in V8 under an experimental flag, is that version of V8 shipped with NodeJS?
07:26
<Ashley Claymore>
Here's the Chromium details: https://github.com/tc39/proposal-structs/blob/main/CHROMIUM-DEV-TRIAL.md
22:12
<shu>
Jack Works: the dev trial doesn't work with node just yet, which needs https://github.com/nodejs/node/pull/47706 to merge