Propose simpler string constant

Alexander Jones alex at weej.com
Thu Dec 17 09:09:28 UTC 2015


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 <Ron.Buckton at microsoft.com>
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:es-discuss-bounces at mozilla.org <javascript:;>]
> On Behalf Of
> > Brendan Eich
> > Sent: Wednesday, December 16, 2015 10:04 AM
> > To: Alican Çubukçuoğlu <alicancubukcuoglu at gmail.com <javascript:;>>; es-
> > discuss at mozilla.org <javascript:;>
> > Subject: Re: Re: Propose simpler string constant
> >
> > On Wed, Dec 16, 2015 at 9:41 AM Alican Çubukçuoğlu
> > <alicancubukcuoglu at gmail.com <javascript:;> <mailto:
> alicancubukcuoglu at gmail.com <javascript:;>> >
> > 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
> es-discuss at mozilla.org <javascript:;>
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20151217/f6cf8592/attachment.html>


More information about the es-discuss mailing list