| 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 |
| 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 |
| 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 |
| 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. |
| 00:49 | <littledan> | What do you mean it wouldn't have the construction logic? Why can't it create an instance? |
| 00:49 | <rbuckton> | We could make a “clone” method on the prototype instead :) |
| 00:49 | <littledan> | The main issue as ron pointed out is the ergonomic of access to proto methods that haven't been defined |
| 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. |
| 00:50 | <rbuckton> | Sorry what issue is this? |
| 00:51 | <littledan> | Providing a useful error if you try to access a method on a foreign struct value that has no associated behavior. 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 |
| 00:52 | <rbuckton> | Oh, I think that would work out well. You would do |
| 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 |
| 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.:
|
| 01:16 | <rbuckton> | especially since I'm opposed to registration based on strings |
| 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. |
| 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? |
| 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 |