00:01 | <rbuckton> | And I do think there's a world where
|
00:01 | <canadahonk> | Rob Palmer: do you have the link to the stdlib breakout session notes? nvm |
00:04 | <bakkot> | did you mean https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-rc/#the---erasablesyntaxonly-option ? |
00:08 | <canadahonk> | đŁ come back to the main plenary room for a summary of breakouts |
00:09 | <rekmarks> | did you mean https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-rc/#the---erasablesyntaxonly-option ? |
00:10 | <sffc> | I'll take notes of the summaries of the presentatoins in https://docs.google.com/document/d/17u9l-TRdEasF5cKHJnTmcBUNRqGQpsYxLNraV8sChfw/edit?tab=t.0 |
00:13 | <rekmarks> | Enum with its current TS implementation is considered an anti-pattern today, not to say that a native enum implementation in ES would not be much better (since most C-like languages have them) |
00:16 | <rbuckton> | I'd still like to hear feedback as to what exactly is considered an anti-pattern regarding
|
00:17 | <ljharb> | (considering the alternative is manually defining a fixed set of forgeable strings, or unforgeable but inconvenient objects or symbols, and manually validating those) |
00:17 | <Ashley Claymore> | Maybe the merging too? |
00:17 | <rbuckton> | Merging? as in enum A { ... } enum A { ... } ? |
00:17 | <Ashley Claymore> | I'd be suprised if a 262 version had that |
00:18 | <rbuckton> | I agree that's an anti-pattern and is something we probably wouldn't want to carry forward. |
00:21 | <bakkot> | enums being numbers is also bad, in my opinion |
00:22 | <bakkot> | it makes it too easy for adding new values to accidentally be a breaking change |
00:23 | <rbuckton> | Regarding Number vs String vs Symbol, my version of the proposal had a solution to that:
|
00:23 | <bakkot> | I would be ok with them being strings but at that point you might as well just use strings |
00:23 | <ljharb> | it's still helpful to simplify validation and enumeration |
00:24 | <rbuckton> | Numeric enums are the most common in C-like languages, and being numbers might be necessary for TS compat. |
00:24 | <bakkot> | yeah the experience from C-like languages is one of the main reasons I am opposed to them being numbers |
00:24 | <rbuckton> | Due to how existing .d.ts files work, it would be almost impossible to change that default behavior for TS. |
00:25 | <bakkot> | understandable, and I wouldn't want to add enums which conflicted with TS, but the conclusion I'd draw is that we should not add enums to JS at all |
00:27 | <ljharb> | would a TS user notice the value of the enum in typical usage? or is it just that a JS consumer would be using it |
00:27 | <rekmarks> | Re: âenums are an antipatternâ, I havenât verified all of the claims in this myself (and itâs a bit sensationalist) but have experienced / agree with a plurality of them: https://dev.to/ivanzm123/dont-use-enums-in-typescript-they-are-very-dangerous-57bh |
00:30 | <rekmarks> | would a TS user notice the value of the enum in typical usage? or is it just that a JS consumer would be using it |
00:32 | <rekmarks> | Re: âenums are an antipatternâ, I havenât verified all of the claims in this myself but have experienced / agree with a plurality of them: https://dev.to/ivanzm123/dont-use-enums-in-typescript-they-are-very-dangerous-57bh |
00:37 | <rbuckton> | Re: âenums are an antipatternâ, I havenât verified all of the claims in this myself (and itâs a bit sensationalist) but have experienced / agree with a plurality of them: https://dev.to/ivanzm123/dont-use-enums-in-typescript-they-are-very-dangerous-57bh |
00:41 | <canadahonk> | https://github.com/linusg/ecmascript-wiki |
00:57 | <rbuckton> |
There is an issue with TS |
01:02 | <rbuckton> | Also, I still think Number values make the most sense for the default, especially when working with Atomics (e.g., .load() , .xor() , etc.) and I/O (protocols, headers, etc.), not to mention bitmasks. I also imagine number comparisons to be generally more efficient than string comparisons. I imagine they're also more readily inlineable into something like a jump table for use with switch . Numbers generally just work in most places. |
01:04 | <rbuckton> | One "compatible" approach I've also considered is that an ES enum might require the of clause if there are any members that are missing initializers. TS enum could elide it (as it does today), but emit enum E of Number {} to JS, or in the case of auto-numbering, emit enum E { A = 0, B = 1, ... } and populate the auto-numbered enums during emit. |
01:45 | <Ashley Claymore> | do we need the
|
01:48 | <Ashley Claymore> | as ADT wouldn't need them right? |
01:48 | <rbuckton> | The of Type syntax is a convenience for those who specifically prefer something like a string or symbol by default for enums. In those cases, the repetition of enum E { A = Symbol(), B = Symbol(), ... } would be unnecessarily unwieldy. |
01:49 | <rbuckton> | It also provides a convenient way to describe the defaulting behavior for both auto numbered enums as well as string and numeric enums: https://github.com/rbuckton/proposal-enum?tab=readme-ov-file#evaluation |
01:50 | <Ashley Claymore> | if it's a connivence could it be a follow on? |
01:51 | <rbuckton> | IMO, the above syntax is a non-starter. const x = enum certainly doesn't help the "erasable syntax" case for TS, and enum.A would prevent future use of enum for any other metaproperty, which was a blocking issue for the the class.x syntax as well. |
01:52 | <Ashley Claymore> | I'd personally be ok with the bare A resolving to the member |
01:52 | <rbuckton> | I would not, unfotunately. |
01:53 | <Ashley Claymore> | how comes? your early example had it bare |
01:53 | <rbuckton> | enum.A would have the exact same issue as class.A , and I've come around to agreeing with that position. |
01:54 | <rbuckton> | One of the motivations for an enum proposal would be to reduce the runtime syntax friction between TS and ES. Proposing a wholly different syntax does not address that concern and would make adoption very difficult. |
01:57 | <Ashley Claymore> | makes sense. but we potentially need the syntax to be at least slightly different if the semantics are not identical? |
01:57 | <rbuckton> | Also, the mechanism for explicit autonumbering as part of emit ends up not being truly "eraseable" as it requires the introduction of temporaries to handle initializers, i.e.:
This is also an example of the problematic type-directed emit in TS today that I hope to fix in the future. I cannot statically know what the value of
|
01:58 | <rbuckton> | The of syntax is an invocation of an explicit mapper function that handles defining the default initializer of each value. |
01:58 | <rbuckton> | Ideally, I would prefer a native syntax where enum E {} is the equivalent of enum E of Number {} , and thus the syntax could be identical in both cases. |
01:59 | <rbuckton> | This would also allow those who have a specific preference around using strings or symbols to express that via, e.g., a linter, while preserving the predominant base case of using numbers. |
02:02 | <Ashley Claymore> | I'm probably in the minority, I prefer the values being explicit. Even if it is repetitive |
02:03 | <Ashley Claymore> | are there other languages where the enum delegates to a runtime protocol to construct the values? |
02:03 | <rbuckton> | The other caveat of TS vs ES enums to address would be the reverse mapping aspect of TS enums, which is great for diagnostics purposes but unreliable for serialization/deserialization use cases. That's why my version of the enum proposal offloads reverse mappings to a symbol protocol and is made accessible via the Enum API. It introduces a more reliable and formal mechanism for parsing and serializing. |
02:03 | <rbuckton> | Python does |
02:04 | <Ashley Claymore> | thanks, I'll check that out |
02:05 | <rbuckton> |
|
02:05 | <Ashley Claymore> | the parts I like the most about the proposal is the self reference during initialisation, and the object being frozen. |
02:05 | <rbuckton> | Also, while not quite runtime, Go uses iota . C# enums use a similar auto-numbering mechanism to the one defined in TypeScript, but are also handled at compile-time. |
02:09 | <rbuckton> | The other benefit to a syntactic
|
02:14 | <rbuckton> | This is also a hard comparison to make, considering the ratio of dynamic to static languages. By nature of JS being dynamic, more things often need to be done at runtime or are expressed via runtime operations (i.e., Object.defineProperty , Reflect.* , etc.). |
02:17 | <rbuckton> | I also hold out hope that a syntactic enum might be able to establish an object shape for the enum declaration that could eventually be used by bytecode generators for specific performance tuning, much like how we hope the fixed shape nature of struct could be utilized. For example, a switch over cases of E.A , E.B could potentially inline those values if it is known that E is an enum with a fixed shape, and thus convert the switch to a jump table. |
02:19 | <rbuckton> | As mentioned in one of the talks today, that's not something we can depend on, but its potentially feasible w/o needing any kind of whole program optimization on the part of the bytecode generator. |
02:19 | <Ashley Claymore> | if enums are mostly static I can see minifiers being able to inline the values |
02:19 | <Ashley Claymore> | the constructors might make that too hard |
02:19 | <rbuckton> | That's already the case in tools like esbuild |
02:19 | <Ashley Claymore> | right, but there isn't a symbol protocol today |
02:20 | <rbuckton> | But that depends on whole program optimization. The enum -ness of E could be encoded into its map/shape and is thus available when collecting type feedback on a switch case |
02:21 | <Ashley Claymore> | doesn't need to be whole program, only need to see the two modules |
02:22 | <Ashley Claymore> | follow the import and look at the export |
02:22 | <rbuckton> | Are you referring to the @@toEnum symbol? |
02:23 | <Ashley Claymore> | I'm not sure if the proposal changed since I last looked |
02:23 | <Ashley Claymore> | I thought the of T looked up a symbol on T |
02:23 | <rbuckton> | We could make those frozen on built-in constructors, so for the most common use cases it can be determined statically. Edge cases using a custom @@toEnum would be slower, but thats pay-to-play. Also, the performance cost is only during startup. |
02:24 | <Ashley Claymore> | I thought we had a rule that we couldn't freeze intrinsics |
02:24 | <rbuckton> | I mean { writable: false, configurable: false } |
02:25 | <Ashley Claymore> | I'd have to defer to TG3 if that fits their model |
02:25 | <rbuckton> | And if that's not viable, then an opt-out if it differs from the expected value. |
02:27 | <Ashley Claymore> | I'd personally be Ok with the possible patterns being baked in statically, without ways to create custom constructors. For strings if someone wanted a constructor that created lowercase or uppercase strings for example doesn't feel like enough of a motivation to introduce the dynamic lookup |
02:27 | <Ashley Claymore> | number+string+symbol sounds more than enough :) |
02:27 | <rbuckton> | Also bigint |
02:28 | <Ashley Claymore> | interesting |
02:28 | <rbuckton> | Also flags, and eventually ADT enums |
02:28 | <Ashley Claymore> | flags are numbers though right |
02:28 | <rbuckton> | Yes, but the auto-numbering behavior differs |
02:28 | <Ashley Claymore> | is bigint for when needing a larger domain of possible flags? |
02:29 | <rbuckton> | Yes, if bigint were fast enough I'd have plenty of TS enum s that I'd make into bigints. In TS we regularly have to worry about running out of space in an SMI |
02:29 | <Ashley Claymore> | I do see the wins, but I also feel like explicit assignment is unambiguious as to what will happen. It's "just JavaScript" :D |
02:29 | <Ashley Claymore> | and the repeitiveness feels like a small price to pay |
02:30 | <rbuckton> | Flags enums would autonumber as 0 , 1 << 0 , 1 << 1 , 1 << 2 , ... |
02:30 | <Ashley Claymore> | I really hope we get the enum proposal and it feels like that's more likely to happen if it's kept simpler |
02:30 | <rbuckton> | Explicit assignment just isn't backwards compatible with TS, unfortunately. |
02:31 | <Ashley Claymore> | could tooling help here, I'd happily write the codemod! |
02:32 | <Ashley Claymore> | also thanks for helping answer my queries, much appreciated |
02:32 | <rbuckton> | The problem is the thousands of existing .d.ts files. Hand-generated .d.ts files can contain enum E { A, B } even though we normally emit them with hardcoded initializers. |
02:32 | <Ashley Claymore> | gotcha |
02:32 | <rbuckton> | We have over a decade of legacy to deal with that ties our hands in many ways. |
02:33 | <Ashley Claymore> | so would need a way to mark the 'new' enums when generating .d.ts |
02:33 | <rbuckton> | No, generating a .d.ts is fine since we always generate with hard-coded initializers. |
02:33 | <rbuckton> | We have no control over hand-rolled .d.ts files |
02:34 | <Ashley Claymore> | I mean we'd preserve the auto-increment type inference for existing .d.ts |
02:34 | <rbuckton> | i.e., much of DefinitelyTyped, any code that's behind the firewall, etc. |
02:35 | <Ashley Claymore> | JS enums could be enum E #{} to differentiate? |
02:35 | <rbuckton> | That's only possible if we preserve auto-incrementing numbers for native enums by default. |
02:36 | <rbuckton> | Why though? What value does that bring? of T at least has some benefits. |
02:36 | <Ashley Claymore> | it's simpler |
02:36 | <Ashley Claymore> | no dynamic lookup |
02:37 | <rbuckton> | Why is dynamic lookup bad for enum E of T {} but ok for class C extends B {} ? |
02:37 | <rbuckton> | I'd put forth that class C extends B is worse because it requires dynamic lookup during new |
02:37 | <Ashley Claymore> | because classes need to extend from an infinite set |
02:38 | <rbuckton> | Number is an infinite set. |
02:38 | <Ashley Claymore> | enums can be a few built in types |
02:38 | <Ashley Claymore> | I mean the set of types |
02:38 | <Ashley Claymore> | not the set of values |
02:38 | <Ashley Claymore> | we can't hard code that classes can only extend from number/string/symbol |
02:38 | <Ashley Claymore> | we can for enum |
02:39 | <rbuckton> | What good does hard coding it do? of T doesn't enforce any constraints on the values of each enum member, it only affects auto-numbering. |
02:39 | <Ashley Claymore> | it's simpler |
02:39 | <rbuckton> | You could say enum E of Number { A = "foo" } |
02:40 | <rbuckton> | I don't think this kind of simpler will pass muster for others on the committee. |
02:40 | <Ashley Claymore> | I think the complexity of of is also not aligned with the feedback we are currently getting in committee to keep proposals simpler |
02:40 | <Ashley Claymore> | for other proposals |
02:40 | <rbuckton> | "simpler" would be enum E { A, B } produces auto-numbered values. That is a tried and true implementation that matches what TS has been doing for a decade |
02:42 | <Ashley Claymore> | Lots of code uses plain object literals for enums today, the biggest downside is not being able to self reference |
02:42 | <rbuckton> | IMO, auto-numbering is a very important part of the feature and is something a large number of existing TS developers rely on. |
02:43 | <rbuckton> | And without some form of auto-numbering, we have no way of making enum work with a pure "erasable types" solution as it would still require additional downlevel emit. |
02:43 | <Ashley Claymore> | I'd be OK if un-initalized names were auto-incrementing |
02:43 | <Ashley Claymore> | strings would need explicit assignment |
02:44 | <rbuckton> | Yes, but ljharb and bakkot would not. |
02:44 | <rbuckton> | of is designed to find a compromise between those positions. |
02:44 | <ljharb> | i donât mind auto increment. But i mildly prefer only explicit |
02:45 | <Ashley Claymore> | if of is the only way to resolve the comittee's constraints I get that. But I'd really like to be sure we've exhausted 'simpler' options. |
02:45 | <rbuckton> | The other benefit to of is to specify the backing type for auto-increment behavior, such that you could have enum E of BigInt { None, A, B } produce bigints instead of numbers. |
02:46 | <ljharb> | the value is imo in covering enumeration and validation, i donât care about the one time that might have to be explicitly written. read > write and all that |
02:46 | <Ashley Claymore> | that benefit seems small (incrementing bigint) |
02:46 | <rbuckton> | enumeration and validation are important, but only a small piece of the pie. |
02:47 | <ljharb> | for me itâs like 99% of it |
02:47 | <bakkot> | My preference continues to be not having enums, rather than trying to rationalize TS enums as a JS feature. |
02:47 | <rbuckton> | Yes, but for me its maybe like 40% of it. |
02:47 | <ljharb> | whatâs the rest? Surely itâs not ânot having to type out a few numbers and/or stringsâ |
02:48 | <ljharb> | types i guess, but im assuming a JS context here :-) |
02:48 | <rbuckton> | My major use cases have been ordered ranges, bitflags/bitmasks, and binary serialization formats (network I/O, binary file/section headers, etc.) |
02:49 | <ljharb> | bitflags only work if you can increment by powers of two, and i donât see how thatâs doable automatically |
02:49 | <rbuckton> | SyntaxKind , for example, uses auto-numbering and pre-defined ranges for fast comparison of AST node kinds. |
02:49 | <ljharb> | and formats are strings which are explicit |
02:50 | <rbuckton> | Its doable with of . |
02:50 | <ljharb> | auto numbering does seem like it make unintentional breaking changes highly likely |
02:50 | <bakkot> | I would be enthusiastic about a native BitSet, possibly backed by an arraybuffer |
02:51 | <bakkot> | (not with syntax though) |
02:51 | <rbuckton> | You can do something similar in Go as well:
|
02:53 | <rbuckton> | As would any unintentional change to your public API. |
02:54 | <ljharb> | sure. But those are harder to do by accident. |
02:54 | <bakkot> | Zig's support for fixed-width ints of any width, with packing into binary representations, is quite nice |
02:55 | <rbuckton> | I would argue that banning auto-numbering, or requiring of String or of Symbol , is something a lint rule could handle, but it isn't a rule I would enforce by default. |
02:56 | <ljharb> | implicitness should be either allowed or prohibited, it shouldnât be pushed to linters |
02:58 | <rbuckton> | I would, in general, be fine with a MVP version that has no @@toEnum and explicitly checks if the expression passed to of is one of the built-in Number , String , Symbol , or BigInt constructors, as that leaves room for future extensibility (i.e., of Enum.BitFlags , of Enum.ADT , etc.) |
02:58 | <ljharb> | stuff itâs ok to push to linters is when itâs a preference; this is different imo. Autonumbering is either fine, or a footgun, so weâd have to make a call |
02:58 | <rbuckton> | I believe the implicitness should be allowed, and is essential for compatibility. |
02:59 | <rbuckton> | Even without of , you can always enforce explicitness if you need, but enum E { A, B } producing numbers would be essential for compatibility. |
02:59 | <ljharb> | what kind of compatibility? |
02:59 | <ljharb> | TS can transpile to explicit numbers |
03:00 | <rbuckton> | Not without running into problems with "legacy" .d.ts files hand written before native enums existed. |
03:00 | <rbuckton> | Its the TS version of "this is already legal JS" |
03:02 | <rbuckton> | You also can't transpile to explicit numbers without either whole program analysis or introducing temporary variables. |
03:03 | <Ashley Claymore> | I'm not following this bit still. Legacy .d.ts would only impact the types, not the emit right? |
03:05 | <rbuckton> | The types describe the runtime behavior. |
03:05 | <Ashley Claymore> | I mean, the existing interpretation of those files doesn't need to change |
03:08 | <rbuckton> | It does if we adopt an interpretation of enum for ES that requires explicit initializers, and then adopts some other behavior for auto-initialization later. |
03:09 | <rbuckton> | Either way, not having auto numbering is incompatible with "erasable types" (i.e., such as ts-blank-space) as we have to inject initializers, or manually auto-number as in the example I mentioned above:
|
03:10 | <Ashley Claymore> | ts-blank-space only erases the parts with no runtime semantics. So it would preserve enums as written |
03:10 | <Ashley Claymore> | as they would be valid 262 |
03:11 | <rbuckton> | Maybe it gets us half way, and if you run with --erasableSyntaxOnly you have to explicitly number your enum values, but I'd still prefer to have auto-numbering. |
03:11 | <ljharb> | right, the point is to make enums non erasable |
03:11 | <rbuckton> | It would not be pleasant to introduce a new *Keyword entry into SyntaxKind and have to shift 250+ entries up one integer. |
03:12 | <ljharb> | prefer is fine, but then itâs not a compat issue? |
03:12 | <ljharb> | It would not be pleasant to introduce a new |
03:12 | <ljharb> | feature not bug |
03:12 | <rbuckton> | I wholeheartedly disagree |
03:12 | <ljharb> | why would it be relevant what number backs the ast nodes? |
03:13 | <rbuckton> | Because we group those nodes for fast comparisons. |
03:13 | <ljharb> | other than to consumers who wouldnât want the numbers to shift |
03:13 | <ljharb> | youâre implying that neighboring integers compare faster in engines? |
03:13 | <rbuckton> | i.e., node.kind >= SyntaxKind.FirstKeyword && node.kind <= SyntaxKind.LastKeyword |
03:13 | <ljharb> | ah |
03:13 | <Ashley Claymore> | how comes we need a new syntax kind? |
03:13 | <ljharb> | so, good api design would suggest designing groups initially that had enough gaps to never run into that problem? |
03:14 | <bakkot> | I think the SyntaxKind use case is quite specific to TS's code base |
03:14 | <rbuckton> | Years ago it was suggested to write a function that converts them to ints, but that's only making the problem 100% worse and killing the performance of that check. |
03:14 | <rbuckton> | I assure you it isn't. |
03:14 | <Ashley Claymore> | alternative would be to add a new flag to the existing syntax kind node |
03:14 | <rbuckton> | That is terrible for memory usage. |
03:17 | <bakkot> | How many programs are making more than a dozen different tagged variants of one kind of thing? |
03:17 | <bakkot> | I have literally only ever done that when writing parsers or general purpose binary formats. |
03:18 | <rbuckton> | Anything using jsdom ? |
03:18 | <rbuckton> | Any DSL involving a tree of disjoint nodes? |
03:18 | <bakkot> | Jsdom itself, yes. Things using it, no. |
03:18 | <bakkot> | How many programs are making DSLs? |
03:18 | <rbuckton> | Games in Unity, or any other JS framework? |
03:18 | <ljharb> | most programs donât deal with a DSL or a tree in first party code |
03:18 | <Ashley Claymore> | wouldn't it only be an extra 64bits * number of enums in program? i.e. orders of magnitudes less impact than adding a prop to the identifier nodes |
03:19 | <rbuckton> | Storing an extra field on every Node just to group the kind of node? This is empirically terrible. We're regularly trying to claw back memory by removing fields we can infer rather than store. |
03:20 | <rbuckton> | And how would you store something like that on the enum itself without having to do some kind of comparison/hashtable lookup just to pull out the group? |
03:20 | <Ashley Claymore> | it's not every node, I think I'm not following the original issue |
03:23 | <rbuckton> | At least in TypeScript's case, ordered integer enum values are a major performance feature. Being able to do fast math on node.kind is essential. That would apply to any application focusing on performance optimization, not just the TS compiler. |
03:24 | <bakkot> | That does not apply to any application for using on performance, just those with dozens of variants of one kind. Which is very very unusual outside of a parser, which most JS programs do not contain. |
03:24 | <ljharb> | also even if the TS codebase canât use native enums, that doesnât mean itâs not a valuable feature for the majority of programs |
03:25 | <Ashley Claymore> | nicolo-ribaudo: explained it to me. I thought the new syntaxKind was to represent these new enum syntax. |
03:26 | <Ashley Claymore> | as opposed to just the general TS change of needing to add any new syntax |
03:26 | <Ashley Claymore> | caught up. sorry for confusion |
03:26 | <rbuckton> | I don't disagree, but I'm trying to thread the needle of:
|
03:27 | <ljharb> | if all can be achieved then great. But some of those donât matter to the majority of codebases, so they should be the first to be sacrificed if needed |
03:28 | <Ashley Claymore> | auto-increment in userland with AOT inlining could be done with a magic comment :D |
03:28 | <Ashley Claymore> | I agree not lovely to build a custom tool for the project |
03:28 | <Ashley Claymore> | but I think the case of these huge enums with 100s of values is rare |
03:29 | <bakkot> | Extremely rare |
03:29 | <rbuckton> | All of those bullets are currently satisfied by the current TS enum syntax. The only case that would not be would be something like "Symbol by default" or "String by default", which would break all but the last bullet point. |
03:30 | <rbuckton> | the of T syntax was suggested to make "Symbol by default" or "String by default" far easier. |
03:30 | <ljharb> | of T seems fine to me fwiw |
03:30 | <Ashley Claymore> | symbol and strings needing to be explicit assignment seems like an OK compromise |
03:31 | <rbuckton> | And that's exactly how current TS enums work (for String, at least. Symbol isn't currently supported, but could be) |
03:31 | <ljharb> | (implicit strings is actually fine with me too, thereâs no footgun there) |
03:31 | <bakkot> | For almost all programs, the benefit of having something which does not make it trivial to introduce breaking changes outweighs the benefit of auto-incrementing values. So the default should not be auto incrementing integers. |
03:32 | <Ashley Claymore> | I like current TS enums! (minus the merging and not being 262) |
03:33 | <rbuckton> | In a world where you had Symbol by default how would that differ from auto-incrementing integers if you never explicitly tried to hard code the value of an enum? |
03:33 | <ljharb> | because the symbols and strings arenât ordered |
03:33 | <rbuckton> | That doesn't matter |
03:33 | <ljharb> | The very ordering/grouping property you went with numbers is why itâs a footgun |
03:33 | <ljharb> | itâs the only thing that matters afaict? |
03:34 | <rbuckton> | If you consider the value to be a black box, which is what Symbol by default implies, then whether the integers are ordered is irrelevant. |
03:34 | <ljharb> | adding a thing shouldnât change other things |
03:34 | <ljharb> | thatâs the concern |
03:34 | <ljharb> | that concern only exists with auto increment, not with implicit values |
03:34 | <rbuckton> | the ordering/grouping property is a performance optimization, not a footgun. If they were Symbols by default, there is no way I could have the same performance optimization. |
03:35 | <ljharb> | itâs both |
03:35 | <rbuckton> | For "Symbol by default", the initialized values change on every application startup |
03:35 | <ljharb> | nobody objects to the perf part from what i can tell, but itâs inseparable from the footgun part. |
03:35 | <ljharb> | thatâs unobservable tho since itâs just identity. So itâs fine. |
03:36 | <bakkot> | the ordering/grouping property is a performance optimization, not a footgun. If they were Symbols by default, there is no way I could have the same performance optimization. |
03:37 | <bakkot> | Even without enums you could do what I do and have a generated file with the mapping of kinda to integers and regenerate whenever it changes. |
03:37 | <bakkot> | This is such a specialized use case. |
03:37 | <rbuckton> | Symbol by default wouldn't work with shared memory multithreading, though Auto-numbering and strings by default would. |
03:37 | <bakkot> | *kinds not kinda |
03:39 | <rbuckton> | Auto-numbering works because the nature of shared struct correlation depends on the module resolution cache, so you can be fairly confident that the enum is evaluated in the same way in both the main and worker threads. Strings work because they would be the same. Symbols would not because they would result in unique values in each thread. |
03:41 | <rbuckton> | This requires something like a hashtable lookup to produce the integer for comparison, which has a major impact on performance. It wouldn't be a solution for this case. |
03:43 | <rbuckton> | e.g., you go from something that is essentially 5 >= 1 && 5 <= 15 to map[sym] >= 1 && map[sym] <= 15 , or x = map[sym]; x >= 1 && x <= 15 , which requires more steps and more stack space in a tight loop/hot path |
03:43 | <bakkot> | I think you misunderstand. The mapping is just like `export const DECL_KIND = 12` |
03:44 | <rbuckton> | That's a compatibility issue, and again blows up the first four bullet points above. |
03:45 | <bakkot> | Right. It only satisfies TS's very niche use case. But other use cases do not have the auto-incrementing constraint. |
03:46 | <bakkot> | Auto-incrementing is a very unusual thing to want and is harmful to most programs. We should not make it easy to reach for. |
03:52 | <rbuckton> | It's getting late. I need to think on this more and chat with my team tomorrow. Unfortunately, the auto-numbering concern has been the biggest blocker for years, IMO. |
05:17 | <rkirsling> | oh man, it hurts that someone has chosen REK for their signifier, given that those are my actual initials đ |
07:03 | <rekmarks> | oh man, it hurts that someone has chosen REK for their signifier, given that those are my actual initials đ |
17:28 | <snek> | can i come to the tg5 event if i didn't register? |
17:31 | <snek> | Michael Ficarra: ^ |
17:32 | <Michael Ficarra> | yep |
19:07 | <Jack Works> |
|
19:10 | <nicolo-ribaudo> | Potentially stupid question, but when we say "auto-increment should be opt-in", can it just be "opt-in" like this?
|
19:11 | <nicolo-ribaudo> | Or, for binary flags,
|
19:12 | <Jack Works> |
auto enum T {} or enum T with Number { a; } (compared to enum T { a = 1 } ) |