@Alex Those languages have this thing called static types, which enable many of those optimizations.
On Thu, Dec 17, 2015, 04:09 Alexander Jones <[email protected]> wrote: > I think we can do better than to follow C#'s lead, if that's the case. I > don't see what the point in `Color.Red - Color.Green` is. Languages like > Rust, Swift, OCaml are providing full Algebraic Data Types that approach > this whole domain from a better level. Also, I don't like the idea of > overloading enum for both sets of combineable flags and sets of distinct > values - that seems like a lack of a good abstraction. Look to Qt for IMO a > pretty good one: http://doc.qt.io/qt-4.8/qflags.html > > Alex > > > On Wednesday, 16 December 2015, Ron Buckton <[email protected]> > wrote: > >> In C#, an enum is a declaration that defines a distinct type consisting >> of a set of named constant values of that type. The distinct type of the >> enum has an underlying numeric base type, such as byte, int, long, etc. By >> default, each constant value is assigned an incrementing integer value >> starting from 0, although this sequence can be interrupted by assigning an >> explicit integer value: >> >> ```cs >> enum Colors { Red, Green, Blue } >> Colors.Red // 0 >> Colors.Green // 1 >> Colors.Blue // 2 >> >> enum Days: byte { Sat = 1, Sun, Mon, Tue, Wed, Thu, Fri } >> Days.Sat // 1 >> Days.Sun // 2 >> ``` >> >> C# enum values can be used with many standard numeric operations, and are >> often heavily used with bitwise operators. A C# enum value is a constant >> value, and is internally treated as a numeric literal by the compiler. In >> any C# enum declaration, only constant numeric values can be explicitly >> assigned to an enum member, although constant reduction is permitted: >> >> ```cs >> enum UriComponents { >> Scheme = 0x1, >> UserInfo = 0x2, >> Host = 0x4, >> Port = 0x8, >> Path = 0x10, >> Query = 0x20, >> Fragment = 0x40, >> AbsoluteUri = Scheme | UserInfo | Host | Port | Path | Query | Fragment >> } >> ``` >> >> Although C# enum values are converted to numeric literals by the >> compiler, their type information is preserved. This allows for an enum type >> to have different behavior from a literal numeric type. One example of this >> behavior is how ToString is handled on an enum value: >> >> ```cs >> enum Numbers { Zero, One, Two } >> (int)Numers.Zero // 0 >> Numbers.Zero.ToString() // Zero >> ``` >> >> The enum type itself has a number of static methods to make it easier to >> program against, including: GetName, GetNames, GetUnderlyingType, >> IsDefined, Parse, and ToObject. Instance members of an enum type include >> HasFlag and CompareTo. >> >> In TypeScript we treat an enum declaration in a fashion similar to a C# >> enum, with respect to how we handle incremental integer values and >> explicitly assigned values. We effectively emit an enum as an object >> literal: >> >> ```ts >> // TypeScript >> enum Colors { Red, Green, Blue } >> >> Colors.Red // 0 >> >> // JavaScript >> var Colors; >> (function (Colors) { >> Colors[Colors[0] = "Red"] = 0; >> Colors[Colors[1] = "Green"] = 1; >> Colors[Colors[2] = "Blue"] = 2; >> })(Colors || (Colors = {})); >> >> Colors.Red // 0 >> ``` >> >> In this way, you can use `Colors.Red` to get the value 0, and `Colors[0]` >> to get the value "Red". As a performance optimization we also have what we >> call "const enums". A const enum can be completely erased by the compiler: >> >> ```ts >> // TypeScript >> const enum Colors { Red, Green, Blue } >> >> Colors.Red // 0 >> >> // JavaScript >> 0 /*Colors.Red*/ // 0 >> ``` >> >> I think a general proposal for ES enums would be a combination of the >> above approaches, with some additions: >> >> * An enum can be a declaration or an expression. >> * The body of an enum consists of a new lexical scope. >> * Enum members are standard JavaScript identifiers. >> * Enum members are automatically assigned an incrementing integer value, >> starting at zero. >> * Enum members can be explicitly assigned to an integer value, or another >> enum value. >> * Within the body of an enum, Enum members can be accessed in the >> initializer without qualification. >> * Within the body of an enum, Enum members are lexically declared names >> and cannot be accessed before they are defined (TDZ). >> * An enum declaration can be called as a function to convert a string or >> numeric value into the enum value, making enum types distinct from numbers >> and from each other. [1] >> * The result of `typeof` on an enum value is `enum`. >> * Enum values support (at least) the following operators, returning an >> enum value of the same type: + (unary), - (unary), ~, + (binary), - >> (binary), | (binary), & (binary), ^ (binary). >> * Any binary operation between two enums of different types is a >> TypeError. [1] >> * Any binary operation between an enum and a number first converts the >> number to the enum type. If the number is not an integer it is a TypeError. >> * Any binary operation between an enum and a string first converts the >> enum into the string value for that enum based on the enum member's >> JavaScript identifier (if present), or the string representation of its >> integer numeric value. [2] >> * Calling Number() with an enum value as its first argument returns its >> underlying number value. >> * Calling String() with an enum value as its first argument returns the >> string value for the enum member that defines the number (if present), or >> the string representation of its integer numeric value. [2] >> * Calling the valueOf() instance method on an enum value has the same >> effect as Number() above. >> * Calling the toString() instance method on an enum value has the same >> effect as String() above. [2] >> * Two enum members on the same enum or differing enum types with the same >> underlying integer value are equivalent (==) but not strictly/reference >> equivalent (===). [1] >> >> I think these rules could satisfy both anyone who needs enum values to be >> numeric (to support bitwise operations, bitmasks, ordinal indices, etc.) >> and those that would like enum values to be unique in a fashion similar to >> using Symbol(). >> >> [1] We have noticed in TypeScript some issues with Symbol-like >> equivalence with enums if you have two versions of the same module in >> NodeJS due to specific version dependencies, where you could have >> a.Color.Red !== b.Color.Red if *a* and *b* are different versions of the >> same module. Generally I think having enum values just really be numbers >> and not differing between == and === is less of a footgun. >> >> [2] If enum values of different types should be === to each other, you >> should not be able to get a different result when you call .ToString(). In >> that case, we could add a static `getName` method to the enum type to get >> the string value for an enum. >> >> Ron >> >> > -----Original Message----- >> > From: es-discuss [mailto:[email protected]] On Behalf Of >> > Brendan Eich >> > Sent: Wednesday, December 16, 2015 10:04 AM >> > To: Alican Çubukçuoğlu <[email protected]>; es- >> > [email protected] >> > Subject: Re: Re: Propose simpler string constant >> > >> > On Wed, Dec 16, 2015 at 9:41 AM Alican Çubukçuoğlu >> > <[email protected] <mailto:[email protected]> > >> > wrote: >> > >> > >> > How are enums declared? >> > ```javascript >> > let myVar = 13; >> > enum myEnum = {Red, Green, Blue}; >> > >> > >> > No `=` between name and `{`. >> > >> > Enumerator scope is a good question. Clearly we do not want global >> scope. >> > Rather, as a declaration immedicately contained by a block or top >> > level, we want lexical scope for the enum name -- and (I think) for the >> enumerators' >> > individual names. >> > >> > What about enumerator name scope for enum in class, without `static`? >> > I'm not sure, but precedent says that the enumerator names define >> > prototype properties. >> > >> > Expression as well as declaration `enum` form follows class and >> > function precedent. Expression form requires a reserved identifier >> > (not sym or sum or whatever), which `enum` has been forever, >> fortunately. >> > >> > I agree symbol values by default, with ` = 0` or some other number >> > than >> > 0 after the first enumerator name, looks confusing. Recall the first >> > use-case in the o.p. was (implicit, should rather be explicit) >> > reflection on the string value that spells the enumerator name. >> > >> > /be >> _______________________________________________ >> es-discuss mailing list >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss >> > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

