gosling.js
gosling.js copied to clipboard
code consistency: prefer ECMAScript private class fields over TypeScript private keyword
TypeScript has a designated syntax for specifying private fields on a class, which we make use of in Gosling.
class MyClass {
private x = 0;
}
TypeScript will keep us accountable and prevent us from accessing x
from outside of MyClass
, but the distinction of private and public fields is a TypeScript-only feature and not enforced at runtime (read: users can call new MyClass().x
in JavaScript).
Since TypeScript's creation, ECMAScript has adopted a standard for specifying "private" fields with private class fields. In TypeScript, these fields function exactly the same as private
, but have the added benefit of being truly private at runtime (read: users can't call new MyClass().#x
)
class MyClass {
#x = 0;
}
I'm not sure how many of our TypeScript classes are exported as a part of Gosling's public API, but I think it would be especially preferable to migrate toward EMCAScript private class fields.
Perhaps a motivating example. @gmod/bam
uses TypeScript private fields, and we ignore their "private-ness" in our data-fetcher. The preferred way to handle this would be to make an upstream change to gmod, adding a new public API, but since they aren't truly private we just ignore it out of convenience. This is not a pattern that we would want users of Gosling.js to adopt or rely on.
https://github.com/gosling-lang/gosling.js/blob/a1977b99c7b2687f1bee8990ce2ca18760572d4d/src/data-fetchers/bam/bam-worker.ts#L208-L228
This seems related to some of the issues @etowahadams is finding with private/public fields in https://github.com/gosling-lang/gosling.js/pull/874. My guess is that we somehow rely on casting our classes to any
, and then accessing a TypeScript private field in a different function. Adopting ECMAScript private fields will keep us more accountable for public/private interfaces in our classes.
I finally got around to reading about EMCAScript private vs Typescript private. Unfortunately, it seems like there are some performance differences between using private field
vs #field
. Using EMCAScript private fields is 82% slower for this simple example. The performance hits are also noted in the Typescript docs.
I haven't gotten around to testing the differences in a real world environment, so perhaps it is not as stark, but perhaps for some applications we may prefer not using #
private fields
Oh very interesting! I did not know this. My thought to move towards ecmascript private fields was to move towards web standards and be more consistent across the code base. I guess for internal APIs we could/should prefer typescript private fields for performance reasons (and because the ts type checker will hold us accountable - except when passing objects to HiGalsss as we’ve discovered). But for any public apis i really think true private fields should be preferred. With that said, I doubt this kind of performance hit would be noticeable to a user unless we were accessing a private field in a very hot loop.
I agree, its unlikely that private fields are going to need to be accessed hundreds of times such that this is going to make a huge difference. My guess would be that over the next few years, modern JavaScript engines are going to improve their performance of ecmascript private fields anyway (apparently Edge's ChakraCore is the leader in this) so it may not be much to worry about.