-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Narrow numbers to const enums #14076
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Please make sure to label your PR with "bug", "new feature" or "breaking change" label(s). |
Snapshot stored with reference name: Test environment: To test a playground add it to the URL, for example: https://babylonsnapshots.z22.web.core.windows.net/refs/pull/14076/merge/index.html#WGZLGJ#4600 Links to test babylon tools with this snapshot: https://playground.babylonjs.com/?snapshot=refs/pull/14076/merge To test the snapshot in the playground with a playground ID add it after the snapshot query string: https://playground.babylonjs.com/?snapshot=refs/pull/14076/merge#BCU1XR#0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll start by saying that I am all for optimizations :-)
We had a long discussion about const enums a long time ago.
Some background (I noticed you addressed some of these points in your description) -
The main issue with const enums is the fact that they are typescript-only feature. So if we already have an enum, they cannot be converted to const enums, because this will not be back-compat. Performance-wise it is much better than standard enums. This is why we have been doing this hybrid public static
mode, instead of using enums on code that requires high-performance.
Personally - I would rather not extend the classes with more public static variables. One reason is that it simply expands the already-large classes that we have, and the other is discoverability. For example, if the example you provided - why would the FOGMODE variables be located in Scene? And though in this examples they do have a proper naming convention, a lot of the times they don't - like the Mesh's side orientation options, for example.
But I believe your suggestion is to improve the already-existing values with const-enums to improve all of the issues I have mentioned before. This maintains back-compat (because JS already has the solution) and (as you say) improves discoverability for typescript devs.
Are there many cases we have those kind of approach? We did try to solve it with the Constants file, which acts roughly like a const enum, in a sense that the build system injects its values to the compiled sources in order to achieve a smaller footprint. The constants are still exported.
In regards to your question - I wonder if the minified version increased as well? The non-minified version's size increased probably due to the comments typescript adds when using const-enums:
export class Scene {
}
/** The fog is deactivated */
Scene.FOGMODE_NONE = 0 /* FogMode.None */;
/** The fog density is following an exponential function */
Scene.FOGMODE_EXP = 1 /* FogMode.Exp */;
/** The fog density is following an exponential function faster than FOGMODE_EXP */
Scene.FOGMODE_EXP2 = 2 /* FogMode.Exp2 */;
/** The fog density is following a linear function. */
Scene.FOGMODE_LINEAR = 3 /* FogMode.Linear */;
Minification should remove those and I expect it to eventually have the size size as before.
A more apparent issue would be documentation (and the playground in js mode) - we generate our typedoc from the declaration files. As many people (us included) are using declaration files in JS dev, they will still see the object "defined", but when trying to use it, they will find that it is not.:
A simple PG - This is expected to work, but it fails, as the object is undefined - https://playground.babylonjs.com/?snapshot=refs/pull/14076/merge#9571GM
TL;dr - I think it's a great suggestion, but it has some aspects that might be problematic. I think the better approach to solve this is use the same architecture as the constants, or maybe even find a better one - a solution that doesn't generate a class full of "public static"s, but still fully support both JS and TS
Thanks for sharing your thoughts @RaananW! To clarify one thing though, TypeScript var FogMode = {
None: 0,
Exp: 1,
Exp2: 2,
Linear: 3,
}; But now I can't seem to repro this, so I don't know if I was using the TS Playground with a pre-release TS version, or maybe I saw it with Babel or something, I can't remember 🤷♂️. I think if we could get the TS compiler to emit the above, it would be pretty good. But the full enum generated with Also, what I saw locally is that the full enum existed in the dev build of the babylon.js file, though as you mentioned it seems to not exist for the Playground build associated with my PR. I don't know why the behavior is different, and I don't know why in my local dev build the enums are emitted to JS since I can't find the |
A nice thing that preserveConstEnum does (which TBH I wasn't aware of) is that it assigns the value while keeping the enum. So, apart from the generated enum (which is string-based) the values are embedded wherever they are used in the framework. I think it might be something we can consider using. We could add some form of a transformer to generate objects instead of enums when using const enum. But that will complicate the build process a bit more. Need to think how possible it is and how long it will take to implement. All in all, i love the suggestion. I think we could benefit from const enums, and I think that in certain cases we could use them instead of Constants or public statics. Especially if we enable the To your last question:
|
This pull request has been marked as stale because it has been inactive for more than 14 days. |
This pull request has been marked as stale because it has been inactive for more than 14 days. Please update to "unstale". |
Closing with no activity |
Babylon has a lot of APIs where a property or variable type is just
number
, and you typically set the value based on a static property of a class (though I've seen plenty of code where it was just set to a number directly). For example:Since the type of
fogMode
is justnumber
, it can be hard to know what value it should be set to (especially for folks who are new to the Babylon API and not aware of this repeated pattern), and is also error prone in that you can easily assign it to an invalid numeric value and not know until runtime.It seems like one simple fix for this could be do to define light weight
const enum
s, something like:It seems like this approach has several benefits:
I see a few open questions with this approach as well though:
if (scene.fogMode && scene.fogMode !== 0)
. This code is technically incorrect, or at least redundant as it is essentially checking if fogMode is zero twice. With the proposed change, this line becomes a compile time error. If the first part of the condition is false, then fogMode is not zero, and so fogMode is narrowed to 1|2|3, which results in the second check producing an error (since 0 is not part of the 1|2|3 union). I would say technically this is actually catching a programming error in the code which is good, but it does mean existing code that does not produce TypeScript errors could produce TypeScrpit errors with this change.I made this a draft PR to get feedback on the proposal. If folks think the pros outweigh the cons, then I would apply this pattern to many more cases. Thoughts?