What do you think about a C# 6 like nameof() expression for

# Stas Berkov (6 years ago)

Can we revisit this issue?

In C# there is nameof, in Swift you can do the same by calling


let keyPath = \Person.mother.firstName

NSPredicate(format: "%K == %@", keyPath, "Andrew")

Let's introduce nameof in ES, please.

Devs from TypeScript don't want to introduce this feature in TypeScript unless it is available in ES ( microsoft/TypeScript#1579 )

This feature is eagarly being asked by TypeScript community.

I understand there are couple issues related to nameof feature in ES. They are: minification and what to do if user already has nameof function.

Minification.

  1. If your code to be minimized be prepared that variable names will also change.

  2. (just a possibility) Minimizer can have option to replace nameof(someVar) with result of nameof function.

What if user already has nameof function.

  1. To maintain status quo we can user nameof function having priority over newly introduced language feature.

  2. OR we can use typeof syntax, e.g. nameof msg.userName (// returns "userName" string)

# Augusto Moura (6 years ago)

Can you list the benefits of having this operators? Maybe with example use cases

If I understand it correctly, the operator fits better in compiled (and typed) languages, most of the use cases don't apply to dynamic Javascript The only legit use case I can think of is helping refactor tools to rename properties (but even mismatch errors between strings and properties names can be caught in compile time using modern Typescript)

Em sex, 14 de jun de 2019 às 10:05, Stas Berkov <stas.berkov at gmail.com> escreveu:

# guest271314 (6 years ago)

Have not tried TypeScript. What are the use cases for JavaScript where TypeScript is not used? Does nameof() check if an object has a specific property name defined ("MutationObserver" in window; window.MutationObserver; "document" in globalThis)?

# Ron Buckton (6 years ago)

The 'nameof' operator provides the string name of a static symbol (in compiler/linker terms, not an ECMAScript 'Symbol'). This is often useful for diagnostics (logging and errors), and gives developers a way to reduce repetition. It is also extremely helpful in editors that support symbolic "rename" refactoring.

While ES functions have a 'name' property, one of the main use cases is to get a string representation of the name of a thing that isn't itself reified as an object, such as a variable, parameter, or module namespace:

import * as ns from "foo";

nameof ns; // "ns"

let fn = function g() {};
fn.name; // "g"
nameof fn; // "fn"

Here is an example of two common use cases:

class C {
  compare(other) {
    if (!(other instanceof C)) {
      throw new TypeError(`Invalid argument: ${nameof other} `);
    }

  set prop(value) {
    this._prop = value;
    this.emit("propertychanged", nameof prop);
  }
}

It's not that a language like TypeScript would need this, but rather that users of an editor like VS Code or WebStorm that have a JavaScript language service would benefit from it.

Ron

# guest271314 (6 years ago)

Not following the module example. Would not ns be an instance of Module where * as ns is used?

For the class example would nameof be equivalent to Object.getOwnPropertyDescriptors(other).name.value?

It's not that a language like TypeScript would need this, but rather that users of an editor like VS Code or WebStorm that have a JavaScript language service would benefit from it.

Is the primary use case a non-simple text editor e.g., not notepad or gedit (GUI) or pico or nano (CLI); where the user is depending on the local program (text editor or "IDE")

for diagnostics (logging and errors)

before actually running the code in a given environment - not to log errors (that is, for example, Uncaught SyntaxError: Identifier 'fn' has already been declared) during code execution?

# Stas Berkov (6 years ago)

ES can benefit from nameof feature the same way as TS. There is no TS specific in it. It was asked to introduce in TS as a workaround since TS is considered as extention of ES.

Case 1. Function guard.

function func1(param1, param2, param3, userName, param4, param5) {
   if (userName == undefined) {
       throw new ArgumentNullError(nameof userName); // `ArgumentNullError`
is a custom error, derived from `Error`, composes error message like
"Argument cannot be null: userName".
   }
}

Case 2. Access extended information an object property. Assume a function

function protoPropertyIsSet(message, property) {
    return message != null && message.hasOwnProperty(property);
}

Then in code you use it as if (protoPropertyIsSet(msg, "expiration_utc_time")) {... }. Having nameof would allow you to do that if (protoPropertyIsSet(msg, nameof msg.expiration_utc_time)) {... }. You get more robust code.

# guest271314 (6 years ago)

Is Case 1 equivalent to a briefer version of

if (userName == undefined) {
  throw new Error(`Argument cannot be null: ${Object.keys({userName})[0]}`);
}

?

If not, how is nameof different?

At Case 2 what is the difference between the use of message.hasOwnProperty(property) and nameof msg.expiration_utc_time?

You get more robust code.

How is "robust" objectively determined?

# Stas Berkov (6 years ago)

Less fragile. Less mess. You can rename field/property without fear you break something (using IDE refactoring tools). With high probablity you will break something when you refactor and have fields hardcoded as strings. Someone can object that you can rename strings as well. Issue here that you can ocassionally change non-related strings that should not be changed even they match or have matching substring.

# Stas Berkov (6 years ago)

Is Case 1 equivalent to a briefer version of

   if (userName == undefined) {
       throw new Error(`Argument cannot be null:
${Object.keys({userName})[0]}`);
   }

Less readable but in this simple case might work. What if we do the following:

Case 1. Function guard.

function func1(options) {
...
   if (options.userName == undefined) {
       throw new ParamNullError(nameof options.userName); //
`ParamNullError` is a custom error, derived from `Error`, composes error
message like "Parameter cannot be null: userName".
   }
}

Case 2. Accessing property extended info e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof object1.property1);

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

# guest271314 (6 years ago)

Terms such as "more robust", "Less fragile." , "Less mess." are subjective. "Fragile" how? What is meant by "mess"?

If the proposal is that nameof is briefer than using shorthand property names or computed property names to get an identifier as a string, then nameof would be less code.

You can rename field/property without fear you break something (using IDE refactoring tools).

The use case appears to be within the context of an IDE?

For users that roll their own code by hand at a simple text editor (GUI or CLI) and do not use an IDE for composing code (or relying on an IDE for logging errors), am not able to discern how nameof is different than using Object.getOwnPropertyDescriptors(other).name.value or Object.keys({userName})[0]. The actual code will need to be tested in different browsers anyway before deployment to get the actual results.

If a user has decided they have to use some form of an "IDE" (which is ultimately an individual choice) to compose code and log errors - while they are writing the code - they can open DevTools at Chromium or Chrome then select Sources => Snippets => New snippet, where

const n = 123;
const n = 456;

will highlight the line where the error occurs - during writing the code - the as a red circle with a transparent "x" in the middle (the same circle with "x" will be shown on DevTools panel with 1 indicating 1 error which can be clicked and will "navigate" DevTools to the line where the error occurs) and hovering over the red circle with the "x" in the middle will provide detail of the error message

Uncaught SyntaxError: Identifier 'n' has already been declared

To run the code press Ctrl+Enter.

--

Case 2. Accessing property extended info e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof object1.property1);

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

Under what circumstances will the 1st example be "broken"?

Again, the term "robustness" might be significant to some, though from perspective here has no clear meaning in code other than being an adjective describing the code. The human applies the descriptor to the code. Some other human has to concur with such a description in order for that term to have any relevance - to them individually. If the term is not adopted as meaningful within the scope of the code by the other human, the term can be omitted as irrelevant. Objectively the only observable traits of code are input and output (and time - if all tests are done at the same machine; or all hardware is listed at the various machines where code is tested as to time), which means that it should not matter how (in code) output is derived as long as the output meets the requirement.

# Ron Buckton (6 years ago)

A module namespace isn’t an instance of Module, it’s a module namespace spec object. If it has a name member, that is because the module you imported has an exported binding called name. But what kind of thing it is isn’t what matters.

nameof just returns a string representation of the static symbolic name of its operand. nameof would be used at runtime (i.e. during code execution), but provides the ability for advanced editors to include it in a “rename” refactoring.

The operand merely needs to be an identifier that exists within the current lexical scope. nameof would not observe TDZ and would not evaluate any expression. The ECMAScript static semantics would merely: 1) check that the identifier provided to nameof is the name of something in the current lexical scope, and 2) replace the expression with a string literal representing the name.

If nameof foo.bar were allowed nameof would not actually evaluate foo.bar, but merely result in ”bar”. nameof does not evaluate anything, it is merely a syntactic transformation by the runtime that becomes a string.

Ron

From: guest271314 <guest271314 at gmail.com>

Sent: Friday, June 14, 2019 10:07 AM To: Ron Buckton <Ron.Buckton at microsoft.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

Not following the module example. Would not ns be an instance of Module where * as ns is used?

For the class example would nameof be equivalent to Object.getOwnPropertyDescriptors(other).name.value?

It's not that a language like TypeScript would need this, but rather that users of an editor like VS Code or WebStorm that have a JavaScript language service would benefit from it.

Is the primary use case a non-simple text editor; e.g., not gedit (GUI) or pico or nano (CLI), where the user is depending on the program

for diagnostics (logging and errors)

within a text editor before actually running the code in a given environment - not to log errors during code execution?

On Fri, Jun 14, 2019 at 4:29 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

The 'nameof' operator provides the string name of a static symbol (in compiler/linker terms, not an ECMAScript 'Symbol'). This is often useful for diagnostics (logging and errors), and gives developers a way to reduce repetition. It is also extremely helpful in editors that support symbolic "rename" refactoring. While ES functions have a 'name' property, one of the main use cases is to get a string representation of the name of a thing that isn't itself reified as an object, such as a variable, parameter, or module namespace:

import * as ns from "foo";
nameof ns; // "ns"
let fn = function g() {};
fn.name<https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Ffn.name&data=02%7C01%7CRon.Buckton%40microsoft.com%7C104ffaa78f6847e3a31708d6f0eab6e3%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636961288212685352&sdata=sBP1RXbppYfrzbSFUaC%2F80IBZk1tUDqdxeVmbuTveSE%3D&reserved=0>; // "g"

nameof fn; // "fn"

Here is an example of two common use cases:

class C {
  compare(other) {
    if (!(other instanceof C)) {
      throw new TypeError(`Invalid argument: ${nameof other} `);
    }
  set prop(value) {
    this._prop = value;
    this.emit("propertychanged", nameof prop);
  }
}

It's not that a language like TypeScript would need this, but rather that users of an editor like VS Code or WebStorm that have a JavaScript language service would benefit from it. Ron

# Ron Buckton (6 years ago)

Since nameof does not actually evaluate anything, the following would be legal:

const x = nameof y; // "y"
const y = 1;

However, the shorthand property name workaround is not legal due to TDZ:

const x = Object.keys({y})[0]; // error due to TDZ
const y = 1;

With the shortand property name workaround you also run into the added runtime overhead of:

  • Constructing an object ({y})
  • Looking up a property (Object.keys)
  • Calling a function (Object.keys)
  • Allocating an array
  • Indexing into the array

Whereas nameof has no runtime overhead, because it would be handled during static semantics.

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of guest271314

Sent: Friday, June 14, 2019 11:17 AM To: Stas Berkov <stas.berkov at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

Terms such as "more robust", "Less fragile." , "Less mess." are subjective. "Fragile" how? What is meant by "mess"?

If the proposal is that nameof is briefer than using shorthand property names or computed property names to get an identifier as a string, then nameof would be less code.

You can rename field/property without fear you break something (using IDE refactoring tools).

The use case appears to be within the context of an IDE?

For users that roll their own code by hand at a text editor and do not use an IDE for composing code (or relying on an IDE for logging errors), am not able to discern how nameof is different than using Object.getOwnPropertyDescriptors(other).name.value or Object.keys({userName})[0]. The actual code will need to be tested in different browsers anyway before deployment to get the actual results.

If a user has decided they have to use some form of a dynamic "IDE" to compose code and log errors - while they are writing the code, they can open DevTools at Chromium or Chrome then select Sources => Snippets => New snippet, where

const n = 123;
const n = 456;

will highlight the line where the error occurs - during writing the code - the as a red circle with a transparent "x" in the middle

```Uncaught SyntaxError: Identifier 'n' has already been declared````

To run the code press ctrl+enter.

On Fri, Jun 14, 2019 at 5:48 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

Less fragile. Less mess. You can rename field/property without fear you break something (using IDE refactoring tools). With high probablity you will break something when you refactor and have fields hardcoded as strings. Someone can object that you can rename strings as well. Issue here that you can ocassionally change non-related strings that should not be changed even they match or have matching substring.

On Fri, Jun 14, 2019 at 9:38 PM guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

Is Case 1 equivalent to a briefer version of

   if (userName == undefined) {
       throw new Error(`Argument cannot be null: ${Object.keys({userName})[0]}`);
   }

?

If not, how is nameof different?

What is the difference between the use of message.hasOwnProperty(property) and nameof msg.expiration_utc_time?

You get more robust code.

How is "robust" objectively determined?

On Fri, Jun 14, 2019 at 5:21 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

ES can befit from nameof feature the same way as TS. There is no TS specific in it. It was ask to introduce in TS as a workaround since TS is considered as extention of ES.

Case 1. Function guard.

function func1(param1, param2, param3, userName, param4, param5) {
   if (userName == undefined) {
       throw new ArgumentNullError(nameof userName); // `ArgumentNullError` is a custom error, derived from `Error`, composes error message like "Argument cannot be null: userName".
   }
}

Case 2. Access extended information an object property. Assume a function

function protoPropertyIsSet(message, property) {
    return message != null && message.hasOwnProperty(property);
}

Then in code you use it as if (protoPropertyIsSet(msg, "expiration_utc_time")) {... }. Having nameof would allow you to do that if (protoPropertyIsSet(msg, nameof msg.expiration_utc_time)) {... }. You get more robust code.

On Fri, Jun 14, 2019 at 5:46 PM Augusto Moura <augusto.borgesm at gmail.com<mailto:augusto.borgesm at gmail.com>> wrote:

Can you list the benefits of having this operators? Maybe with example use cases

If I understand it correctly, the operator fits better in compiled (and typed) languages, most of the use cases don't apply to dynamic Javascript The only legit use case I can think of is helping refactor tools to rename properties (but even mismatch errors between strings and properties names can be caught in compile time using modern Typescript)

Em sex, 14 de jun de 2019 às 10:05, Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> escreveu:

Can we revisit this issue?

In C# there is nameof, in Swift you can do the same by calling


let keyPath = \Person.mother.firstName

NSPredicate(format: "%K == %@", keyPath, "Andrew")

Let's introduce nameof in ES, please.

Devs from TypeScript don't want to introduce this feature in TypeScript unless it is available in ES ( microsoft/TypeScript#1579nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FTypeScript%2Fissues%2F1579&data=02|01|ron.buckton%40microsoft.com|9b2c54f48f5d4505fb1008d6f0f494c9|72f988bf86f141af91ab2d7cd011db47|1|0|636961330684601102&sdata=P7VAkHGEM1WeVpzpovf9TxXOdkzcuQgcBsoGwMNqmuA%3D&reserved=0 )

This feature is eagarly being asked by TypeScript community.

I understand there are couple issues related to nameof feature in ES. They are: minification and what to do if user already has nameof function.

Minification.

  1. If your code to be minimized be prepared that variable names will also change.

  2. (just a possibility) Minimizer can have option to replace nameof(someVar) with result of nameof function.

What if user already has nameof function.

  1. To maintain status quo we can user nameof function having priority over newly introduced language feature.

  2. OR we can use typeof syntax, e.g. nameof msg.userName (// returns "userName" string)


es-discuss mailing list es-discuss at mozilla.org<mailto:es-discuss at mozilla.org> mail.mozilla.org/listinfo/es-discussnam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.mozilla.org%2Flistinfo%2Fes-discuss&data=02|01|ron.buckton%40microsoft.com|9b2c54f48f5d4505fb1008d6f0f494c9|72f988bf86f141af91ab2d7cd011db47|1|0|636961330684611108&sdata=hyL72vBqg5ecV6O%2BO33sWVN%2BQ2SOqeFyHGGKSw%2BH5fk%3D&reserved=0

-- Atenciosamente,

Augusto Borges de Moura

# guest271314 (6 years ago)

A module namespace isn’t an instance of Module, it’s a module namespace spec object. If it has a name member, that is because the module you imported has an exported binding called name. But what kind of thing it is isn’t what matters.

If Object.getOwnPropertyDescriptors(ns) is used within <script type="module"> then Symbol(Symbol.toStringTag): {value: "Module", writable: false, enumerable: false, configurable: false} will also be part of the output. If Object.keys(ns) is used Symbol(Symbol.toStringTag) will not be part of output.

Good points about the overhead of using existing JavaScript features as substitute for nameof. Considered that when composing the code. Still not sure what exactly the use of nameof is outside of an IDE environment?

Since nameof does not actually evaluate anything, the following would be legal:

const x = nameof y; // "y"
const y = 1;

Interesting. y would be able to be evaluated before const y = 1 is defined?

Or, is the output of nameof y not related to the const variable declaration y defined at the next line?

If that example is correct as to expected output, would that not lead to false-positive as to y being defined or not? That is, what occurs if the second line does not exist in the code?

# Stas Berkov (6 years ago)

guest271314, what is you point against nameof feature?

If you don't like it - don't use it. Why prohibit this feature for those who find it beneficial?

I see nameof beneficial in following cases

Case 1. Function guard.

function func1(options) {
...
   if (options.userName == undefined) {
       throw new ParamNullError(nameof options.userName); //
`ParamNullError` is a custom error, derived from `Error`, composes
error message like "Parameter cannot be null: userName".
 // `Object.keys({options.userName})[0]` will not work here
   }
}

Case 2. Accessing property extended info Those ES functions that accept field name as string. e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof
object1.property1);
 // `Object.keys({options1.property1})[0]` will not work here

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

It would make devs who use IDE more productive and make their life easier. Why not give them such possiblity and make them happy?

# guest271314 (6 years ago)

Am neither for nor against the proposal. Do not entertain "like"s or "dislike"s in any field of endeavor. Am certainly not in a position to prohibit anything relevant JavaScript. Do what thou wilt shall be the whole of the Law.

Have yet to view a case where code will be "broken" by nameof not being a JavaScript feature. "robustness", as already mentioned, is a subjective adjective that is not capable of being objectively evaluated as to code itself. That description is based on preference or choice.

In lieu of the proposal being specificed, use the posted code example of Object.keys() that "works".

function func1({userName = void 0} = {}) {
  console.assert(userName !== undefined, [{userName}, "property needs to be defined"])
}

provides a direct notification that the property value is required to be defined - though nameof will not prevent the value from being set as "undefined" or null or an empty string "", or a WeakMap, etc., for which nameof does not solve the issue of certain specific sets of characters being required as a value of the property. Note that the example code of "Function guard" posted thus far does not first check if options is passed at all, for which nameof will not provide any asssitance.

Usually try to meet requirement by means already available (implemented and shipped) in FOSS browsers. Have no interest in TypeScript (or, in general, any third-party JavaScript library not shipped with FOSS browsers) or using an IDE (which does not substitute for actually testing the code in the environment outside the confines of an IDE, where the actual implementation can vary widely from the published specification and between different environments which purport to have implemented a given specification).

FWIW, have no objection to the proposal.

# Ron Buckton (6 years ago)

Interesting. y would be able to be evaluated before y is defined?

I very explicitly stated that nameof y would not evaluate its operand. Evaluation of nameof would merely result in a string containing the name of the binding referenced by the operand.

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of guest271314

Sent: Friday, June 14, 2019 12:09 PM To: Stas Berkov <stas.berkov at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

A module namespace isn’t an instance of Module, it’s a module namespace spec object. If it has a name member, that is because the module you imported has an exported binding called name. But what kind of thing it is isn’t what matters.

If Object.getOwnPropertyDescriptors(ns) is used within <script type="module"> Symbol(Symbol.toStringTag): {value: "Module", writable: false, enumerable: false, configurable: false} will also be part of the output. If Object.keys(ns) is used Symbol(Symbol.toStringTag) will not be part of output.

Since nameof does not actually evaluate anything, the following would be legal:

const x = nameof y; // "y"
const y = 1;

Interesting. y would be able to be evaluated before y is defined?

On Fri, Jun 14, 2019 at 6:01 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

Is Case 1 equivalent to a briefer version of

if (userName == undefined) { throw new Error(Argument cannot be null: ${Object.keys({userName})[0]}); }

Less readable but in this simple case might work.
What if we do the following:
Case 1. Function guard.

function func1(options) { ... if (options.userName == undefined) { throw new ParamNullError(nameof options.userName); // ParamNullError is a custom error, derived from Error, composes error message like "Argument cannot be null: userName". } }


Case 2. Accessing property extended info
e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof object1.property1);

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

On Fri, Jun 14, 2019 at 9:48 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

Less fragile. Less mess. You can rename field/property without fear you break something (using IDE refactoring tools).
With high probablity you will break something when you refactor and have fields hardcoded as strings.
Someone can object that you can rename strings as well.
Issue here that you can ocassionally change non-related strings that should not be changed even they match or have matching substring.

On Fri, Jun 14, 2019 at 9:38 PM guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

Is Case 1 equivalent to a briefer version of

if (userName == undefined) { throw new Error(Argument cannot be null: ${Object.keys({userName})[0]}); }


?

If not, how is ```nameof``` different?

What is the difference between the use of ```message.hasOwnProperty(property)``` and ```nameof msg.expiration_utc_time```?

> You get more robust code.

How is "robust" objectively determined?




On Fri, Jun 14, 2019 at 5:21 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

ES can befit from `nameof` feature the same way as TS. There is no TS specific in it.
It was ask to introduce in TS as a workaround since TS is considered as extention of ES.

Case 1. Function guard.

function func1(param1, param2, param3, userName, param4, param5) { if (userName == undefined) { throw new ArgumentNullError(nameof userName); // ArgumentNullError is a custom error, derived from Error, composes error message like "Argument cannot be null: userName". } }


Case 2. Access extended information an object property.
Assume a function

function protoPropertyIsSet(message, property) { return message != null && message.hasOwnProperty(property); }

Then in code you use it as `if (protoPropertyIsSet(msg, "expiration_utc_time")) {... }`.
Having `nameof` would allow you to do that `if (protoPropertyIsSet(msg, nameof msg.expiration_utc_time)) {... }`.
You get more robust code.

On Fri, Jun 14, 2019 at 5:46 PM Augusto Moura <augusto.borgesm at gmail.com<mailto:augusto.borgesm at gmail.com>> wrote:

Can you list the benefits of having this operators? Maybe with example use cases

If I understand it correctly, the operator fits better in compiled
(and typed) languages, most of the use cases don't apply to dynamic
Javascript
The only legit use case I can think of is helping refactor tools to
rename properties (but even mismatch errors between strings and
properties names can be caught in compile time using modern
Typescript)

Em sex, 14 de jun de 2019 às 10:05, Stas Berkov
<stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> escreveu:
>
> Can we revisit this issue?
>
>
> In C# there is `nameof`, in Swift you can do the same by calling
>
> ```
>
> let keyPath = \Person.mother.firstName
>
> NSPredicate(format: "%K == %@", keyPath, "Andrew")
>
> ```
>
> Let's introduce `nameof` in ES, please.
>
>
> Devs from TypeScript don't want to introduce this feature in TypeScript unless it is available in ES ( https://github.com/microsoft/TypeScript/issues/1579<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FTypeScript%2Fissues%2F1579&data=02%7C01%7Cron.buckton%40microsoft.com%7Ca5837d2939a0425fa12a08d6f0fbc6c3%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636961361537318083&sdata=otJOApnMAGMe24nAB0tLyRcMzMPAkaSAzt%2BBLim%2FMP4%3D&reserved=0> )
>
> This feature is eagarly being asked by TypeScript community.
>
>
> I understand there are couple issues related to `nameof` feature in ES. They are: minification and what to do if user already has `nameof` function.
>
>
> Minification.
>
> 1. If your code to be minimized be prepared that variable names will also change.
>
> 2. (just a possibility) Minimizer can have option to replace `nameof(someVar)` with result of `nameof` function.
>
>
>
> What if user already has `nameof` function.
>
> 1. To maintain status quo we can user `nameof` function having priority over newly introduced language feature.
>
> 2. OR we can use `typeof` syntax, e.g. `nameof msg.userName` (// returns "userName" string)
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.mozilla.org%2Flistinfo%2Fes-discuss&data=02%7C01%7Cron.buckton%40microsoft.com%7Ca5837d2939a0425fa12a08d6f0fbc6c3%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636961361537328075&sdata=H2sPmDZRfgkgd4zDs2klkrUbldqXU3w%2FYtGjEzNz3uw%3D&reserved=0>



--
Atenciosamente,

Augusto Borges de Moura
# Jordan Harband (6 years ago)

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

# Ron Buckton (6 years ago)

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

If you are using an editor that supports rename refactoring, its generally easier to rename the symbol foo and have all references (including nameof foo) be updated. You cannot safely automatically rename 'foo' to 'bar' since an editor or language service cannot guarantee that by the string 'foo' you meant “the text of the identifier foo”.

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of Jordan Harband

Sent: Friday, June 14, 2019 2:29 PM To: guest271314 <guest271314 at gmail.com>

Cc: es-discuss <es-discuss at mozilla.org>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

On Fri, Jun 14, 2019 at 1:31 PM guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

Am neither for nor against the proposal. Do not entertain "like"s or "dislike"s in any field of endeavor. Am certainly not in a position to prohibit anything relevant JavaScript. Do what thou wilt shall be the whole of the Law.

Have yet to view a case where code will be "broken" by nameof not being a JavaScript feature. "robustness", as already mentioned, is a subjective adjective that is not capable of being objectively evaluated as to code itself. That description is based on preference or choice.

In lieu of the proposal being specificed, use the posted code example of Object.keys() that "works".

function func1({userName = void 0} = {}) {
  console.assert(userName !== undefined, [{userName}, 'property needs to be defined'])
}

provides a direct indication that the property value is required to be defined. Note that the example code posted thus far does not first check if options is passed at all, for which nameof will not provide any asssitance.

Usually try to meet requirement by means already available in FOSS browsers. Have no interest in TypeScript or using an IDE.

FWIW, have no objection to the proposal.

On Fri, Jun 14, 2019 at 7:53 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

guest271314, what is you point against nameof feature?

If you don't like it - don't use it. Why prohibit this feature for those who find it beneficial?

I see nameof beneficial in following cases

Case 1. Function guard.

function func1(options) {
...
   if (options.userName == undefined) {
       throw new ParamNullError(nameof options.userName); //
`ParamNullError` is a custom error, derived from `Error`, composes
error message like "Parameter cannot be null: userName".
 // `Object.keys({options.userName})[0]` will not work here
   }
}

Case 2. Accessing property extended info Those ES functions that accept field name as string. e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof
object1.property1);
 // `Object.keys({options1.property1})[0]` will not work here

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

It would make devs who use IDE more productive and make their life easier. Why not give them such possiblity and make them happy?

# guest271314 (6 years ago)

How is that behaviour related to the use cases presented by OP? Would such behaviour not lead to false-positive relevant to the 2 use cases?

# Augusto Moura (6 years ago)

Fri, 14 jun 2019 - 18:29, Jordan Harband <ljharb at gmail.com> wrote:

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

Exactly, if you already have the name of the property beforehand in design time why not write it as a string literal

Again, the only justifiable use case is refactoring tools, but even today that can be arranged with static code analysis

You can safe guard a string literal to be a property of a type in Typescript with a bit of handwork

interface Options {
  userName?: string;
}

// If you change the property in the interface without changing here, Typescript
// will raise a error informing that 'userName' is not a valid key of Options
const userNameKey: keyof Options = 'userName';

if (options.userName === undefined) {
  throw new ParamNullError(userNameKey);
}
# Ron Buckton (6 years ago)

I’m not sure I understand what you mean by “false-positive” in this instance.

Consider this case:

const someObject = { value: 1 };
function setValue(value /*1*/) {
  if (typeof value /*2*/ !== "number") throw new TypeError(`Number expected: ${nameof value /*3*/}`);
  someObject["value" /*4*/] = value /*5*/;
}

If you rename the parameter value of the function setValue in an editor with a rename refactoring, you want to rename the symbols at 1, 2, 3, and 5, but not the string at 4.

Ron

From: guest271314 <guest271314 at gmail.com>

Sent: Friday, June 14, 2019 2:43 PM To: Ron Buckton <Ron.Buckton at microsoft.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

How is that behaviour related to the use cases presented by OP? Would such behaviour not lead to false-positive relevant to the 2 use cases?

On Fri, Jun 14, 2019 at 9:36 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

If you are using an editor that supports rename refactoring, its generally easier to rename the symbol foo and have all references (including nameof foo) be updated. You cannot safely automatically rename 'foo' to 'bar' since an editor or language service cannot guarantee that by the string 'foo' you meant “the text of the identifier foo”.

From: es-discuss <es-discuss-bounces at mozilla.org<mailto:es-discuss-bounces at mozilla.org>> On Behalf Of Jordan Harband

Sent: Friday, June 14, 2019 2:29 PM To: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Cc: es-discuss <es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

On Fri, Jun 14, 2019 at 1:31 PM guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

Am neither for nor against the proposal. Do not entertain "like"s or "dislike"s in any field of endeavor. Am certainly not in a position to prohibit anything relevant JavaScript. Do what thou wilt shall be the whole of the Law.

Have yet to view a case where code will be "broken" by nameof not being a JavaScript feature. "robustness", as already mentioned, is a subjective adjective that is not capable of being objectively evaluated as to code itself. That description is based on preference or choice.

In lieu of the proposal being specificed, use the posted code example of Object.keys() that "works".

function func1({userName = void 0} = {}) {
  console.assert(userName !== undefined, [{userName}, 'property needs to be defined'])
}

provides a direct indication that the property value is required to be defined. Note that the example code posted thus far does not first check if options is passed at all, for which nameof will not provide any asssitance.

Usually try to meet requirement by means already available in FOSS browsers. Have no interest in TypeScript or using an IDE.

FWIW, have no objection to the proposal.

On Fri, Jun 14, 2019 at 7:53 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

guest271314, what is you point against nameof feature?

If you don't like it - don't use it. Why prohibit this feature for those who find it beneficial?

I see nameof beneficial in following cases

Case 1. Function guard.

function func1(options) {
...
   if (options.userName == undefined) {
       throw new ParamNullError(nameof options.userName); //
`ParamNullError` is a custom error, derived from `Error`, composes
error message like "Parameter cannot be null: userName".
 // `Object.keys({options.userName})[0]` will not work here
   }
}

Case 2. Accessing property extended info Those ES functions that accept field name as string. e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof
object1.property1);
 // `Object.keys({options1.property1})[0]` will not work here

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

It would make devs who use IDE more productive and make their life easier. Why not give them such possiblity and make them happy?

# guest271314 (6 years ago)

I’m not sure I understand what you mean by “false-positive” in this instance.

Was referring to

const x = nameof y; // "y"
const y = 1;

Where y if is undefined an error Uncaught ReferenceError: Cannot access 'y' before initialization is not expected to be thrown? Is y declared globally, using const or let, or not at all before being referenced at nameof y; // "y"? The use case described by OP

function func1(param1, param2, param3, userName, param4, param5) {
   if (userName == undefined) {
       throw new ArgumentNullError(nameof userName); // `ArgumentNullError`
is a custom error, derived from `Error`, composes error message like
"Argument cannot be null: userName".
   }
}

checks if userName was undefined before using nameof. If error checking is an emphasized portion of the proposal, why should an error (y being undefined though referenced) be ignored when referencing an undefined identifier though focus be placed on on coercing a name from a different potentially undefined property?

Consider this case:

const someObject = { value: 1 };
function setValue(value /*1*/) {
  if (typeof value /*2*/ !== "number") throw new TypeError(`Number
expected: ${nameof value /*3*/}`);
  someObject["value" /*4*/] = value /*5*/;
}

If you rename the parameter value of the function setValue in an editor with a rename refactoring, you want to rename the symbols at 1, 2, 3, and 5, but not the string at 4.

Not gathering the purpose or coding value of nameof usage in that case. If the value is not a "number" then why does the value or name matter?

Since the primary use case appears to be an editor environment, why cannot the editor be programmed to recognize the custom JavaScript nameof function or operator? Then it would not matter if this board concurred with the nameof functionality or not. Both CLI and GUI editors (and JavaScript) are generally extensible.

Some time ago incorporated very basic features into gedit for HTML templates. Now simply write the code by hand and test in different environments, without taking the time to customize or rely on an editor - take the time to test the code where the code will actually be run where errors, if any, can be evaluated in the context in which a specific output is expected. Should be a similar process to create custom scripts for the various editor environments where users rely on such programs for code composition. As mentioned earlier do not rely on "an editor with name refactoring" to compose code. Though do not object to extending code (language) to meet requirements. The code has to be tested (outside of the editor environments) anyway. Test the code itself, here, not the editor.

What needs to be implemented outside of what the users which propose for nameof cannot implement themselves?

# Ron Buckton (6 years ago)

It doesn’t matter what the value of ‘y’ is, just what the lexical name of y is. nameof wouldn’t refer to y as an expression, its just pointing to the identifier.

From: guest271314 <guest271314 at gmail.com>

Sent: Friday, June 14, 2019 10:03 PM To: Ron Buckton <Ron.Buckton at microsoft.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

I’m not sure I understand what you mean by “false-positive” in this instance.

Was referring to

const x = nameof y; // "y"

const y = 1;

Where y is undefined an error is not expected to be thrown? Is y declared globally, using const or let, or not at all? The use case described by OP

function func1(param1, param2, param3, userName, param4, param5) {

if (userName == undefined) {

   throw new ArgumentNullError(nameof userName); // `ArgumentNullError`

is a custom error, derived from Error, composes error message like

"Argument cannot be null: userName".

} checks if userName was undefined before using nameof. If error checking is a substantial portion of the proposal, why should an error (y being undefined though referenced) be ignored when referencing an undefined identifier though concentrate on coercing a name from a different potentially undefined property?

Consider this case:

const someObject = { value: 1 };
function setValue(value /*1*/) {
  if (typeof value /*2*/ !== "number") throw new TypeError(`Number expected: ${nameof value /*3*/}`);
  someObject["value" /*4*/] = value /*5*/;
}

If you rename the parameter value of the function setValue in an editor with a rename refactoring, you want to rename the symbols at 1, 2, 3, and 5, but not the string at 4.

Not gathering the purpose or value of nameof usage in that case. If the value is not a "number" then why does the value or name matter?

Since the primary use case appears to be an editor environment, why cannot the editor be programmed to recognize the custom JavaScript nameof```` function or operator? Then it would not matter if this board concurred with thenameoffunctionality or not. Both CLI and GUI editors (and JavaScript) are generally extensible. FWIW, some time ago incorporated features into gedit for HTML templates; should be a similar process to create custom scripts for the various editor environments where users rely on such programs for code composition; now simply write the code by hand and test in different environments, without taking the time to customize or rely on an editor - take the time to test the code where the code will actually be run where errors, if any, can be evaluated in the context in which a specific output is expected. To each their own. What needs to be implemented outside of what the users which advocate fornameof``` cannot implement themselves?

As mentioned earlier do not rely on "an editor with name refactoring" to compose code. The code has to be tested (outside of the editor environments) anyway. Test the code itself, here, not the editor.

On Fri, Jun 14, 2019 at 9:49 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

I’m not sure I understand what you mean by “false-positive” in this instance.

Consider this case:

const someObject = { value: 1 };
function setValue(value /*1*/) {
  if (typeof value /*2*/ !== "number") throw new TypeError(`Number expected: ${nameof value /*3*/}`);
  someObject["value" /*4*/] = value /*5*/;
}

If you rename the parameter value of the function setValue in an editor with a rename refactoring, you want to rename the symbols at 1, 2, 3, and 5, but not the string at 4.

Ron

From: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Sent: Friday, June 14, 2019 2:43 PM To: Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>>

Cc: es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

How is that behaviour related to the use cases presented by OP? Would such behaviour not lead to false-positive relevant to the 2 use cases?

On Fri, Jun 14, 2019 at 9:36 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

If you are using an editor that supports rename refactoring, its generally easier to rename the symbol foo and have all references (including nameof foo) be updated. You cannot safely automatically rename 'foo' to 'bar' since an editor or language service cannot guarantee that by the string 'foo' you meant “the text of the identifier foo”.

From: es-discuss <es-discuss-bounces at mozilla.org<mailto:es-discuss-bounces at mozilla.org>> On Behalf Of Jordan Harband

Sent: Friday, June 14, 2019 2:29 PM To: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Cc: es-discuss <es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

On Fri, Jun 14, 2019 at 1:31 PM guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

Am neither for nor against the proposal. Do not entertain "like"s or "dislike"s in any field of endeavor. Am certainly not in a position to prohibit anything relevant JavaScript. Do what thou wilt shall be the whole of the Law.

Have yet to view a case where code will be "broken" by nameof not being a JavaScript feature. "robustness", as already mentioned, is a subjective adjective that is not capable of being objectively evaluated as to code itself. That description is based on preference or choice.

In lieu of the proposal being specificed, use the posted code example of Object.keys() that "works".

function func1({userName = void 0} = {}) {
  console.assert(userName !== undefined, [{userName}, 'property needs to be defined'])
}

provides a direct indication that the property value is required to be defined. Note that the example code posted thus far does not first check if options is passed at all, for which nameof will not provide any asssitance.

Usually try to meet requirement by means already available in FOSS browsers. Have no interest in TypeScript or using an IDE.

FWIW, have no objection to the proposal.

On Fri, Jun 14, 2019 at 7:53 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

guest271314, what is you point against nameof feature?

If you don't like it - don't use it. Why prohibit this feature for those who find it beneficial?

I see nameof beneficial in following cases

Case 1. Function guard.

function func1(options) {
...
   if (options.userName == undefined) {
       throw new ParamNullError(nameof options.userName); //
`ParamNullError` is a custom error, derived from `Error`, composes
error message like "Parameter cannot be null: userName".
 // `Object.keys({options.userName})[0]` will not work here
   }
}

Case 2. Accessing property extended info Those ES functions that accept field name as string. e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof
object1.property1);
 // `Object.keys({options1.property1})[0]` will not work here

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

It would make devs who use IDE more productive and make their life easier. Why not give them such possiblity and make them happy?

# guest271314 (6 years ago)

It doesn’t matter what the value of ‘y’ is, just what the lexical name of y is. nameof wouldn’t refer to y as an expression, its just pointing to the identifier.

Was not referring to the value of y. At that point in the example code

const x = nameof y; // "y"
const y = 1;

the identifer y does not exist.

Was there an expected presumption that y was defined globally in the code prior to the const y = 1; declaration at the next line (which would be a different y variable than the variable on the next line declared with const)?

Does the example code actually expect the const declaration y on the next line to be capable of being referenced on the current line before the declaration ("initialization") on the next line occurs in the code?

A variable declared using const cannot be referenced before "lexical declaration" or "initialization". That fact can be utilized for an alternative approach to meet requirement of "Case 1. Function guard.". Tested at Chromium 76 and Firefox 69. Have not used MS browser (or browserstack) in some time. Have not tried the code at Safari either, though the code is capable of adjustment for any JavaScript environment which throws a ReferenceError under the same case (referencing const variable before declaration or initialization)

function func1(param1, param2, param3, userName, param4, param5) {
  if (userName === undefined) {
    try {
      // throws ReferenceError
      // Firefox 69: ReferenceError: "can't access lexical declaration `userName' before initialization"
      // Chromium 76: ReferenceError: Cannot access 'userName' before initialization
      const userName = userName;
    } catch (e) {
      // match identifier at Firefox, Chromium ReferenceError message
      // adjust RegExp for IE/Edge, Safari, etc.
      const nameof = e.message.match(/(?!`|')[^\s]+(?=')/g).pop();
      throw new Error(`"Argument cannot be null: ${nameof}"`);
    }
  } else {
    // do stuff
    console.log(userName);
  }
}

try {
  func1(1, 2, 3); // throws error
} catch (e) {
  console.error(e); // get name of variable identifier
}

try {
  func1(1, 2, 3, 4); // logs userName at console
} catch (e) {
  console.error(e); // should not be reached
}
# Ron Buckton (6 years ago)

At that point in the example code the identifer y does not exist.

That is not entirely incorrect. The identifier y exists, but its binding has not been initialized, otherwise you couldn’t refer to y in this case:

const f = () => y;

let y = 1;

That fact can be utilized for an alternative approach to meet requirement of "Case 1. Function guard.".

I don’t disagree that there are “alternative approaches” to ‘nameof’ for many cases, but they all incur overhead.

At the end of the day, ‘nameof’ is a convenience feature that provides an incremental “quality of life” improvement, much like shorthand property assignments were a convenience feature (i.e. how hard is it to write { foo: foo }). It’s not something that would be as much of a game changer to the language as async/await or yield were, but it would be a fairly easily spec’d and nice-to-have capability.

From: guest271314 <guest271314 at gmail.com>

Sent: Saturday, June 15, 2019 2:50 PM To: Ron Buckton <Ron.Buckton at microsoft.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

It doesn’t matter what the value of ‘y’ is, just what the lexical name of y is. nameof wouldn’t refer to y as an expression, its just pointing to the identifier.

Was not referring to the value of y. At that point in the example code the identifer y does not exist. That is, unless there was an expected presumption that y was defined globally prior to the const y = 1; declaration at the next line. Even then a variable declared using const cannot be referenced before "lexical declaration" or "initialization". That fact can be utilized for an alternative approach to meet requirement of "Case 1. Function guard.". Tested at Chromium 76 and Firefox 69. Have not used MS browser (or browserstack) in some time. Have not tried the code at Safari either, though the code is capable of adjustment for any JavaScript environment which throws a ReferenceError under the same case

function func1(param1, param2, param3, userName, param4, param5) {
  if (userName === undefined) {
    try {
      // throws ReferenceError
      // Firefox 69: ReferenceError: "can't access lexical declaration `userName' before initialization"
      // Chromium 76: ReferenceError: Cannot access 'userName' before initialization
      const userName = userName;
    } catch (e) {
      // match identifier at Firefox, Chromium ReferenceError message
      // adjust RegExp for IE/Edge, Safari, etc.
      const nameof = e.message.match(/(?!`|')[^\s]+(?=')/g).pop();
      throw new Error(`"Argument cannot be null: ${nameof}"`);
    }
  } else {
    // do stuff
    console.log(userName);
  }
}

try {
  func1(1, 2, 3); // throws error
} catch (e) {
  console.error(e); // get name of variable identifier
}

try {
  func1(1, 2, 3, 4); // logs userName at console
} catch (e) {
  console.error(e); // should not be reached
}

On Sat, Jun 15, 2019 at 9:37 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

It doesn’t matter what the value of ‘y’ is, just what the lexical name of y is. nameof wouldn’t refer to y as an expression, its just pointing to the identifier.

From: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Sent: Friday, June 14, 2019 10:03 PM To: Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>>

Cc: es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

I’m not sure I understand what you mean by “false-positive” in this instance.

Was referring to

const x = nameof y; // "y"

const y = 1;

Where y is undefined an error is not expected to be thrown? Is y declared globally, using const or let, or not at all? The use case described by OP

function func1(param1, param2, param3, userName, param4, param5) {

if (userName == undefined) {

   throw new ArgumentNullError(nameof userName); // `ArgumentNullError`

is a custom error, derived from Error, composes error message like

"Argument cannot be null: userName".

} checks if userName was undefined before using nameof. If error checking is a substantial portion of the proposal, why should an error (y being undefined though referenced) be ignored when referencing an undefined identifier though concentrate on coercing a name from a different potentially undefined property?

Consider this case:

const someObject = { value: 1 };
function setValue(value /*1*/) {
  if (typeof value /*2*/ !== "number") throw new TypeError(`Number expected: ${nameof value /*3*/}`);
  someObject["value" /*4*/] = value /*5*/;
}

If you rename the parameter value of the function setValue in an editor with a rename refactoring, you want to rename the symbols at 1, 2, 3, and 5, but not the string at 4.

Not gathering the purpose or value of nameof usage in that case. If the value is not a "number" then why does the value or name matter?

Since the primary use case appears to be an editor environment, why cannot the editor be programmed to recognize the custom JavaScript nameof```` function or operator? Then it would not matter if this board concurred with thenameoffunctionality or not. Both CLI and GUI editors (and JavaScript) are generally extensible. FWIW, some time ago incorporated features into gedit for HTML templates; should be a similar process to create custom scripts for the various editor environments where users rely on such programs for code composition; now simply write the code by hand and test in different environments, without taking the time to customize or rely on an editor - take the time to test the code where the code will actually be run where errors, if any, can be evaluated in the context in which a specific output is expected. To each their own. What needs to be implemented outside of what the users which advocate fornameof``` cannot implement themselves?

As mentioned earlier do not rely on "an editor with name refactoring" to compose code. The code has to be tested (outside of the editor environments) anyway. Test the code itself, here, not the editor.

On Fri, Jun 14, 2019 at 9:49 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

I’m not sure I understand what you mean by “false-positive” in this instance.

Consider this case:

const someObject = { value: 1 };
function setValue(value /*1*/) {
  if (typeof value /*2*/ !== "number") throw new TypeError(`Number expected: ${nameof value /*3*/}`);
  someObject["value" /*4*/] = value /*5*/;
}

If you rename the parameter value of the function setValue in an editor with a rename refactoring, you want to rename the symbols at 1, 2, 3, and 5, but not the string at 4.

Ron

From: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Sent: Friday, June 14, 2019 2:43 PM To: Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>>

Cc: es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

How is that behaviour related to the use cases presented by OP? Would such behaviour not lead to false-positive relevant to the 2 use cases?

On Fri, Jun 14, 2019 at 9:36 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

If you are using an editor that supports rename refactoring, its generally easier to rename the symbol foo and have all references (including nameof foo) be updated. You cannot safely automatically rename 'foo' to 'bar' since an editor or language service cannot guarantee that by the string 'foo' you meant “the text of the identifier foo”.

From: es-discuss <es-discuss-bounces at mozilla.org<mailto:es-discuss-bounces at mozilla.org>> On Behalf Of Jordan Harband

Sent: Friday, June 14, 2019 2:29 PM To: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Cc: es-discuss <es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

nameof whateverObject.keys({ whatever })[0], but I'm a bit confused why it'd be better to type nameof foo in code, rather than 'foo' - if you change foo to bar, you have to change both of them anyways.

On Fri, Jun 14, 2019 at 1:31 PM guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

Am neither for nor against the proposal. Do not entertain "like"s or "dislike"s in any field of endeavor. Am certainly not in a position to prohibit anything relevant JavaScript. Do what thou wilt shall be the whole of the Law.

Have yet to view a case where code will be "broken" by nameof not being a JavaScript feature. "robustness", as already mentioned, is a subjective adjective that is not capable of being objectively evaluated as to code itself. That description is based on preference or choice.

In lieu of the proposal being specificed, use the posted code example of Object.keys() that "works".

function func1({userName = void 0} = {}) {
  console.assert(userName !== undefined, [{userName}, 'property needs to be defined'])
}

provides a direct indication that the property value is required to be defined. Note that the example code posted thus far does not first check if options is passed at all, for which nameof will not provide any asssitance.

Usually try to meet requirement by means already available in FOSS browsers. Have no interest in TypeScript or using an IDE.

FWIW, have no objection to the proposal.

On Fri, Jun 14, 2019 at 7:53 PM Stas Berkov <stas.berkov at gmail.com<mailto:stas.berkov at gmail.com>> wrote:

guest271314, what is you point against nameof feature?

If you don't like it - don't use it. Why prohibit this feature for those who find it beneficial?

I see nameof beneficial in following cases

Case 1. Function guard.

function func1(options) {
...
   if (options.userName == undefined) {
       throw new ParamNullError(nameof options.userName); //
`ParamNullError` is a custom error, derived from `Error`, composes
error message like "Parameter cannot be null: userName".
 // `Object.keys({options.userName})[0]` will not work here
   }
}

Case 2. Accessing property extended info Those ES functions that accept field name as string. e.g.

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

vs

const descriptor1 = Object.getOwnPropertyDescriptor(object1, nameof
object1.property1);
 // `Object.keys({options1.property1})[0]` will not work here

2nd variant (proposed) has more chances not to be broken during refactoring (robustness).

It would make devs who use IDE more productive and make their life easier. Why not give them such possiblity and make them happy?

# guest271314 (6 years ago)

const f = () => y;

let y = 1;

is different (dissimilar) code from the original example code referenced

const x = nameof y; // "y"
const y = 1;

How is that example related to the nameof proposal?

Does that example seek to extend referencing const declarations before the initialization? Or, can that example be set aside? Can you kindly clarify how that example is different from attempting to reference a const variable before initialization (which would, at the outset, be more than simply a nameof operator)?

I don’t disagree that there are “alternative approaches” to ‘nameof’ for many cases, but they all incur overhead.

What overhead is incurred by the approach using const, try..catch and ReferenceError?

Given that a ReferenceError is thrown now when attempting to reference a variable declared using const before initialization where the message property includes the name of the variable, either the specification now defines to do so, and, or, the implementers are already getting the name of the idetifier as a string and outputting the expected result of nameof (identifier name) in a similar context. Thus, the code already exists and is already being implemented at ReferenceError. It would appear it is now a matter of locating that source code in browser implementations and abstracting the process to a nameof function.

Therefore, from the point of view of what potentially already exists in specification and, or is already implemented in browsers, nameof as a standalone function or operator does not appear to be outside of the scope of what browsers are already doing. Abstracting nameof to a standalone function should be possible - using what already exists.

Have you looked into the source code of browsers that implement const to determine the issues, if any, as to utilizing the existiing implementation(s) of ReferenceError to facilitate nameof while avoiding incurring the described "overhead" of using workarounds to achieve the same output?

# Ron Buckton (6 years ago)

Sorry, I meant to say “not entirely correct”.

From: Ron Buckton Sent: Saturday, June 15, 2019 3:03 PM To: guest271314 <guest271314 at gmail.com>

Cc: es-discuss at mozilla.org Subject: RE: Re: What do you think about a C# 6 like nameof() expression for

At that point in the example code the identifer y does not exist.

That is not entirely incorrect. The identifier y exists, but its binding has not been initialized, otherwise you couldn’t refer to y in this case:

# guest271314 (6 years ago)

Sorry, I meant to say “not entirely correct”.

You have not yet confirmed if in fact the expected output is referencing a variable declared using const on the current line before initialization on the next line (or for that matter N lines down from the current line).

That example appears to deviate from the purpose and usage of const, beyond the scope of nameof, and if were implemented, a ReferenceError should not be thrown when a const variable that has yet to be initialized on the next line is referred to on the current line?

Firefox

const f = (() => y)(); // ReferenceError: can't access lexical declaration `y' before initialization
let y = 1;

Chromium

const f = (() => y)(); // Uncaught ReferenceError: Cannot access 'y' before initialization
let y = 1;

Aside from that example, the code which essentially already implements nameof should be able to be found in the code which implements ReferenceError relevant to const.

# Ron Buckton (6 years ago)
const x = nameof y
const y = 1;

x would have the value “y”. It would not matter if y were initialized or had yet been reached during execution. It does not deviate from the purpose of let or const, because you are not accessing the value of the identifier.

Also consider that this is legal ECMAScript in a module:

export { y }
const y = 1;

The binding for y exists within the same block scope, it just has not yet been initialized. Exporting it via export { y }, closing over it via () => y, or accessing it via nameof y would all be the same. In all three cases you are accessing the binding of y, not the value of y. Even in the () => y case, you don’t access the value of y until you execute the function.

From: guest271314 <guest271314 at gmail.com>

Sent: Saturday, June 15, 2019 3:57 PM To: Ron Buckton <Ron.Buckton at microsoft.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

Sorry, I meant to say “not entirely correct”.

You have not yet confirmed if in fact the expected output is referencing a variable declared using const on the current line before initialization on the next line.

That example appears to deviate from the purpose and usage of const, beyond the scope of nameof, and if were implemented, a ReferenceError should not be thrown when a const variable that has yet to be initialized on the next line is referred to on the current line?

Aside from that example, the code which essentially already implements nameof should be able to be found in the code which implements ReferenceError relevant to const.

On Sat, Jun 15, 2019 at 10:47 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

Sorry, I meant to say “not entirely correct”.

From: Ron Buckton Sent: Saturday, June 15, 2019 3:03 PM To: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Cc: es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>

Subject: RE: Re: What do you think about a C# 6 like nameof() expression for

At that point in the example code the identifer y does not exist.

That is not entirely incorrect. The identifier y exists, but its binding has not been initialized, otherwise you couldn’t refer to y in this case:

# guest271314 (6 years ago)

What should occur where the code is

const x = nameof y

await new Promise(resolve => setTimeout(resolve, 100000)); // should x be "y" here?

await new Promise(resolve => setTimeout(resolve, 200000)); // should x be "y" here?

await Promise.all([new Promise(resolve => setTimeout(resolve, 300000)), ...doStuff()]); // should x be "y" here?

// what happens where errors are thrown in the code above and line where y is initialized is not reached?
do {
  await stuff()
} while (1);

const y = 1;

?

In the above example code, if y is declared as a JavaScript plain object, could not the value of y be (arbitrarily) mutated by the above code initiated before the actual initialization by polling to check if y is initialized or not using try..catch and ReferenceError?

The immediately invoked arrow function example (where a RefeferenceError is thrown) appears to indicaate that to output the expected result of nameof within the context of the code example

const x = nameof y

const y = 1;

is a proposal for more than only getting the name of an declared and initialized variable?

Should a RefefenceError not be thrown simply because nameof is used in this case

const f = (() => nameof y)(); // ReferenceError: can't access lexical declaration `y' before initialization
let y = 1;

?

# Ron Buckton (6 years ago)

What should occur where the code is

It would be "y" in all 3 places.

... is a proposal for more than only getting the name of an declared and initialized variable?

It is a proposal for getting the name of a declared variable. Whether it is initialized does not matter.

Should a RefefenceError not be thrown simple because nameof is used?

No, an error is not thrown. ECMAScript is much more nuanced. Block scoped variables from 'let' or 'const' exist and can be referenced (via closure or export, currently) anywhere within the same block scope, even before they are initialized. Until they have been initialized (the line of code contain the declaration has been reached and evaluated), they exist in a "Temporal Dead Zone" (TDZ). Attempting to dereference them (i.e. access or store a value) while in this TDZ is what results in the ReferenceError.

At no point does the nameof operator dereference the variable, so no error need be thrown.

From: guest271314 Sent: Saturday, June 15, 4:29 PM Subject: Re: Re: What do you think about a C# 6 like nameof() expression for To: Ron Buckton Cc: es-discuss at mozilla.org

What should occur where the code is

const x = nameof y
await new Promise(resolve => setTimeout(resolve, 100000)); // should x be "y" here?

await new Promise(resolve => setTimeout(resolve, 200000)); // should x be "y" here?

await Promise.all([new Promise(resolve => setTimeout(resolve, 300000)), ...doStuff()]); // should x be "y" here?

const y = 1;

?

The immediately invoked arrow function example (where a RefeferenceError is thrown) appears to demonstrate that to output the expected result of nameof within the context of the code example

const x = nameof y
const y = 1;

is a proposal for more than only getting the name of an declared and initialized variable?

Should a RefefenceError not be thrown simple because nameof is used?

On Sat, Jun 15, 2019 at 11:16 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

const x = nameof y
const y = 1;

x would have the value “y”. It would not matter if y were initialized or had yet been reached during execution. It does not deviate from the purpose of let or const, because you are not accessing the value of the identifier.

Also consider that this is legal ECMAScript in a module:

export { y }
const y = 1;

The binding for y exists within the same block scope, it just has not yet been initialized. Exporting it via export { y }, closing over it via () => y, or accessing it via nameof y would all be the same. In all three cases you are accessing the binding of y, not the value of y. Even in the () => y case, you don’t access the value of y until you execute the function.

From: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Sent: Saturday, June 15, 2019 3:57 PM To: Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>>

Cc: es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>

Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

Sorry, I meant to say “not entirely correct”.

You have not yet confirmed if in fact the expected output is referencing a variable declared using const on the current line before initialization on the next line.

That example appears to deviate from the purpose and usage of const, beyond the scope of nameof, and if were implemented, a ReferenceError should not be thrown when a const variable that has yet to be initialized on the next line is referred to on the current line?

Aside from that example, the code which essentially already implements nameof should be able to be found in the code which implements ReferenceError relevant to const.

On Sat, Jun 15, 2019 at 10:47 PM Ron Buckton <Ron.Buckton at microsoft.com<mailto:Ron.Buckton at microsoft.com>> wrote:

Sorry, I meant to say “not entirely correct”.

From: Ron Buckton Sent: Saturday, June 15, 2019 3:03 PM To: guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>>

Cc: es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>

Subject: RE: Re: What do you think about a C# 6 like nameof() expression for

At that point in the example code the identifer y does not exist.

That is not entirely incorrect. The identifier y exists, but its binding has not been initialized, otherwise you couldn’t refer to y in this case:

# guest271314 (6 years ago)

What is the use case for nameof being used as a lookahead before variable initialization?

Since some human has to write const and let and choose the variable name, why cannot the same human write the variable name as a string and maintain a map of all variable names in each required scope?

Taking the proposal a step further, any and all declared variables in any scope could be set at a Map object with key, value pair being name, value (handle variables not set at Map, if allowed, based on requirement). Which would remedy using const and let or var at all - all variables are set at a Map immediately having a unique name and a value. MapInstance.get("key")

For the purposes of nameof as descibed in this proposal a Set might suffice

// NAMEOF is always dynamic list of let, const declarations in current scope 
console.log(NAMEOF); // ["x", "y"]; [{name:"x", line:5}, {name:"y", line:7}] 
// should resolve be in the list even if not declared using const or let?
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000))); 
const x = nameof y
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000)));
const y = 1;
# Isiah Meadows (6 years ago)

I've got a few code bases where I do a lot of stuff like func(person, "person"), and it'd be pretty useful to avoid the duplication.

I'd prefer something more direct like nameof binding, nameof binding.key, and nameof binding[key], where it returns the expression at that parameter position as the "name", with a more convoluted fallback algorithm to handle destructuring and local references sensibly. (It should only consider parse-time data, and it should always strip whitespace and unnecessary parentheses to keep it on a single line.) The required stack space for this is just a single object pointer, and it's not like you can do weird things with eval with it.

For security, there is the concern of unexpected passing of data through parameters (think: getSensitive("sensitive string") as a parameter), but this can be addressed on the minifier side via a directive and on the language side by blocking all name sharing cross-realm (making them just canonical strings derived from values instead).

# guest271314 (6 years ago)

Since nameof does not actually evaluate anything, the following would be legal:

const x = nameof y; // "y"
const y = 1;

At line 1 adjacent to nameof how does the user know that there will be later declared variable named y?

What is the expected output of x where the code does not contain a previous or later declared variable named y?

const x = nameof y; // ?
const z = 1;
# Isiah Meadows (6 years ago)

Here's my opinion:

  • If y is directly visible in scope and is neither a parameter or destructured binding, nameof y should just evaluate to "y". This should be agnostic to whether the binding has been declared yet, so in your example, x should be set to "y".
  • If y is entirely undeclared, it should be a runtime ReferenceError in the same way it is when accessing undefined globals. So in your second example, I'd expect it to throw before even attempting assignment

Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# guest271314 (6 years ago)
  • If y is directly visible in scope and is neither a parameter or destructured binding, nameof y should just evaluate to "y". This should be agnostic to whether the binding has been declared yet, so in your example, x should be set to "y".

The 1st question at esdiscuss.org/topic/what-do-you-think-about-a-c-6-like-nameof-expression-for#content-33 remains:

Without having composed or previously read the source code, at line 1 adjacent to nameof how does the user know that there will be later declared variable named y?

# Frederick Stark (6 years ago)

guest271314, your examples are all completely incorrect anyway since all variable declarations (including let and const) are hoisted to the top of the scope, so when nameof y is evaluated, y is already declared in the scope.

The special behaviour introduced with let and const is that they set up a "Temporal Dead Zone" where attempts to set or get their value before the line where they are declared in code throws an exception. Since nameof doesn't care about the value, only the name of the variable, it would not need to throw an exception. Of course, were this proposal to be taken seriously, it could be specced either way

# guest271314 (6 years ago)

your examples are all completely incorrect anyway

"incorrect" as to precisely what?

# guest271314 (6 years ago)

The user MUST already know the exact identifier name or an error will be thrown for the original proposal use cases and additional use case for nameof

const x = nameof y; // "y"
const y = 1;

making the need for nameof moot - given that the user cannot then rationally state that the identifier as a string will somehow be mispelled if they are able to write the exact name of the identifer at nameof 100% of the time.

The original proposal does not appear to be automated; the user does not acquire knowledge of the variables that they do not already know. Proven by the fact that the user MUST write the variable name adjacent to nameof themselves as a literal identifier.

That leaves the use case of getting ALL of the names of the identifiers in the current scope

// NAMEOF is always dynamic list of let, const declarations in current scope
console.log(NAMEOF); // ["x", "y"]; [{name:"x", line:5}, {name:"y", line:7}]
// should resolve be in the list even if not declared using const or let?
await new Promise(resolve => setTimeout(resolve,
Math.floor(Math.random() * 1000)));
const x = nameof y
await new Promise(resolve => setTimeout(resolve,
Math.floor(Math.random() * 1000)));
const y = 1;

without having to already know the name of the identifiers, as is required by the original proposal; which essentially negates itself as the string literal 'y' is briefer than nameof y.

nameof, if anything, should provide a detail to coding that the user does not already know or have to know in order to not have an error thrown by referencing a non-existent identifier (where the user would have to guess e.g., try..catch, ReferenceError what the identifier name is if they did not already know by first writing or reading the code; that is, virtually impossible - without standardized identifiers where no user deviates from said naming convention).

If the proposal is based on automation it seems sensible to simply get all of the identifer names (let, const, class, etc.) in the current scope first, with optional name and line number; while also being able to handle the case of (protoPropertyIsSet(msg, nameof msg.expiration_utc_time)) {... }.

# Frederick Stark (6 years ago)

your examples are all completely incorrect anyway "incorrect" as to precisely what?

Keep reading the email mate. Incorrect as to your understanding of how the language works and at what point variables are defined.

The user MUST already know the exact identifier name

It's not an issue to need to know the name of the identifier. In fact, as you correctly pointed out, it's necessary. If I'm understanding it correctly, the value of the proposal is to make it easier to refactor (especially with variable renaming tools) without leaving behind string literals that no longer match the variable name.

I've run into this issue before, but it's been a relatively minor pain for me personally. So I can see some use for the proposal, though I suspect it would see most of it's use in tooling. On the other hand, it might add unnecessary complexity to the language, which should be avoided. Overall I'm very mildly supportive.

That leaves the use case of getting ALL of the names of the identifiers in the current scope

I have not seen anyone proposing this, so there's no reason to criticize it yet.

Obligatory disclaimer: not a TC39 member, no decision making power or influence on process

# Jordan Harband (6 years ago)

again, Object.keys({ y })[0] will give you the string y, and will survive refactoring tools. you can even do function nameof(obj) { return Object.keys(obj)[0]; } and then nameof({ y }).

Obviously it's slightly less ergonomic than nameof y would be - but adding new syntax is very expensive, so there'd need to be overwhelming evidence that this pattern is commonly used enough, and that userland workarounds like my nameof function were insufficient.

# Ron Buckton (6 years ago)

Object.keys({ y })[0] will give you the string y, and will survive refactoring tools

No it won’t. Given the following:

let foo /*1*/ = 1;
let x = { foo /*2*/ };

In VSCode, if you rename ‘foo’ to ‘bar’ at /1/, you get this:

let bar = 1;
let x = { foo: bar };

If you rename ‘foo’ to ‘bar’ at /2/, you get this:

let foo = 1;
let x = { bar: foo };

Rename only renames one side of the symbol, either the property name or the captured binding, but not both.

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of Jordan Harband

Sent: Sunday, June 16, 2019 10:35 PM To: Frederick Stark <coagmano at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

again, Object.keys({ y })[0] will give you the string y, and will survive refactoring tools. you can even do function nameof(obj) { return Object.keys(obj)[0]; } and then nameof({ y }).

Obviously it's slightly less ergonomic than nameof y would be - but adding new syntax is very expensive, so there'd need to be overwhelming evidence that this pattern is commonly used enough, and that userland workarounds like my nameof function were insufficient.

On Sun, Jun 16, 2019 at 10:13 PM Frederick Stark <coagmano at gmail.com<mailto:coagmano at gmail.com>> wrote:

your examples are all completely incorrect anyway "incorrect" as to precisely what?

Keep reading the email mate. Incorrect as to your understanding of how the language works and at what point variables are defined.

The user MUST already know the exact identifier name

It's not an issue to need to know the name of the identifier. In fact, as you correctly pointed out, it's necessary. If I'm understanding it correctly, the value of the proposal is to make it easier to refactor (especially with variable renaming tools) without leaving behind string literals that no longer match the variable name.

I've run into this issue before, but it's been a relatively minor pain for me personally. So I can see some use for the proposal, though I suspect it would see most of it's use in tooling. On the other hand, it might add unnecessary complexity to the language, which should be avoided. Overall I'm very mildly supportive.

That leaves the use case of getting ALL of the names of the identifiers in the current scope

I have not seen anyone proposing this, so there's no reason to criticize it yet.

Obligatory disclaimer: not a TC39 member, no decision making power or influence on process On Jun 17 2019, at 2:42 pm, guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

The user MUST already know the exact identifier name or an error will be thrown for the original proposal and additional use case for nameof

const x = nameof y; // "y" const y = 1; making the need for nameof moot given that the user cannot then rationally state that the identifier as a string will somehow be mispelled if they are able to write the exact name of the identifer at nameof 100% of the time.

That leaves the use case of getting ALL of the names of the identifiers in the current scope

// NAMEOF is always dynamic list of let, const declarations in current scope console.log(NAMEOF); // ["x", "y"]; [{name:"x", line:5}, {name:"y", line:7}] // should resolve be in the list even if not declared using const or let? await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000)));

const x = nameof y await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000)));

const y = 1;

without having to already know the name of the identifiers, as is required by the original proposal, which essentially negates itself as the string literal 'y' is briefer than nameof y.

On Mon, Jun 17, 2019 at 4:19 AM Frederick Stark <coagmano at gmail.com<mailto:coagmano at gmail.com>> wrote:

guest271314, your examples are all completely incorrect anyway since all variable declarations (including let and const) are hoisted to the top of the scope, so when nameof y is evaluated, y is already declared in the scope.

The special behaviour introduced with let and const is that they set up a "Temporal Dead Zone" where attempts to set or get their value before the line where they are declared in code throws an exception. Since nameof doesn't care about the value, only the name of the variable, it would not need to throw an exception. Of course, were this proposal to be taken seriously, it could be specced either way

On Jun 17 2019, at 10:15 am, guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

  • If y is directly visible in scope and is neither a parameter or

destructured binding, nameof y should just evaluate to "y". This should be agnostic to whether the binding has been declared yet, so in your example, x should be set to "y".

The 1st question at esdiscuss.org/topic/what-do-you-think-about-a-c-6-like-nameof-expression-for#content-33nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fesdiscuss.org%2Ftopic%2Fwhat-do-you-think-about-a-c-6-like-nameof-expression-for%23content-33&data=02|01|ron.buckton%40microsoft.com|cbc2c8f5e9614533e30e08d6f2e594ef|72f988bf86f141af91ab2d7cd011db47|1|0|636963465244030598&sdata=0jx0f3hXTqN3gfvuWWDh1BiuomZfI3eDdGXetyWSOtk%3D&reserved=0 remains:

Without having composed or previously read the source code, at line 1 adjacent to nameof how does the user know that there will be later declared variable named y?

On Sun, Jun 16, 2019 at 7:04 AM Isiah Meadows <isiahmeadows at gmail.com<mailto:isiahmeadows at gmail.com>> wrote:

Here's my opinion:

  • If y is directly visible in scope and is neither a parameter or destructured binding, nameof y should just evaluate to "y". This should be agnostic to whether the binding has been declared yet, so in your example, x should be set to "y".
  • If y is entirely undeclared, it should be a runtime ReferenceError in the same way it is when accessing undefined globals. So in your second example, I'd expect it to throw before even attempting assignment

Isiah Meadows contact at isiahmeadows.com<mailto:contact at isiahmeadows.com>

www.isiahmeadows.comnam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.isiahmeadows.com&data=02|01|ron.buckton%40microsoft.com|cbc2c8f5e9614533e30e08d6f2e594ef|72f988bf86f141af91ab2d7cd011db47|1|0|636963465244040592&sdata=ncNlzUB9%2FRJmg7%2Bt1vAM4UtxeAMm62ditqH%2BJh2f2kQ%3D&reserved=0

# guest271314 (6 years ago)

In VSCode, if you rename ‘foo’ to ‘bar’ at /1/, you get this:

How is VSCode related to JavaScript?

Is the proposal really based on creating nameof in JavaScript to workaround output at a text editor?

Why not file a bug with the individuals who write the code for VSCode or just write a text editor code from scratch which does what you want as to "refactoring"? Or write the code by hand and test the code to avoid having to rely on any text editor to catch your mistakes?

If no mistakes will be made as to writing the identifier y next to nameof then no mistakes should be make writing the string 'y' at each location where the identifier as a string is found.

As for replacing the named identifier in a text editor, simply include surrounding space characters around the identifier when finding and replacing \sy\s, even a basic text editor such as gedit or even notepad can do that. Can the editor not handle basic search and replace (plnkr.co/edit/xiLQRX?p=preview)?

Does any code get written by archaic paper and pencil when the power goes out and reliance on a specific text editor or "refactoring tools" cannot be sustained, does the generator get turned on so that the text editor can check for mistakes, or is that a signal to take the rest of the day off?

Why use a text editor or IDE or refactoring tools that do not do what you want them to do?

Roll your own editor that does exectly what you want it to do?

How does nameof in JavaScript solve issues or lead to expected output at a text editor?

# Ron Buckton (6 years ago)

How is VSCode related to JavaScript?

You have ignored the context from Jordan’s email (emphasis added):

again, Object.keys({ y })[0] will give you the string y, and will survive refactoring tools. you can even do function nameof(obj) { return Object.keys(obj)[0]; } and then nameof({ y }).

VSCode is a popular editor that supports JavaScript and is a refactoring tool. Rename refactoring was the subject I was responding to.

There are a number of reasons VSCode has implemented rename refactoring in this fashion. Not the least of which is that an editor cannot fully understand user intent. Let us say, for example, you are working with Gulp:

const cwd /*1*/ = ".";
gulp.src("*.js", { cwd /*2*/ });

If you were to rename cwd at (1) and it also renamed the cwd property at (2), you would have introduced an error in the call because a cwd option to gulp has a special meaning. Since the editor doesn’t know the intent of the user may be to rename both symbols, it remains conservative and choses only to rename the binding and its references, producing:

const currentDir = ".";
gulp.src("*.js", { cwd: currentDir });

There is also the issue of collisions:

const foo /*1*/ = 1;
f({ foo /*2*/, bar: 2 });

If I were to use a refactoring tool to rename foo at (1) to bar, it would not be safe to rename the property at (2) as well as it would introduce a semantic error that would prevent the entire script from executing.

In the context of Jordan’s email, that means that Object.keys({ y })[0] would not necessarily survive refactoring tools.

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of guest271314

Sent: Monday, June 17, 2019 7:40 AM Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

In VSCode, if you rename ‘foo’ to ‘bar’ at /1/, you get this:

How is VSCode related to JavaScript?

Is the proposal really based on creating nameof in JavaScript to workaround output at a text editor?

Why not file a bug with the individuals who write the code for VSCode or just write a text editor code from scratch which does what you want as to "refactoring". Or write the code by hand and test the code to avoid having to rely on any text editor to catch your mistakes?

# Ron Buckton (6 years ago)

… there'd need to be overwhelming evidence that this pattern is commonly used enough …

As it pertains to C#: search?l=C%23&q=nameof&type=Code. There are at least 860k uses of the nameof operator in C# projects on GitHub, and that’s before GitHub search gave up because there were too many results and the search took too long:

[cid:image001.png at 01D5252A.DFBBAB10]

There’s unfortunately no way to check for this pattern in JavaScript because the feature doesn’t exist.

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of Jordan Harband

Sent: Sunday, June 16, 2019 10:35 PM To: Frederick Stark <coagmano at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Re: What do you think about a C# 6 like nameof() expression for

again, Object.keys({ y })[0] will give you the string y, and will survive refactoring tools. you can even do function nameof(obj) { return Object.keys(obj)[0]; } and then nameof({ y }).

Obviously it's slightly less ergonomic than nameof y would be - but adding new syntax is very expensive, so there'd need to be overwhelming evidence that this pattern is commonly used enough, and that userland workarounds like my nameof function were insufficient.

On Sun, Jun 16, 2019 at 10:13 PM Frederick Stark <coagmano at gmail.com<mailto:coagmano at gmail.com>> wrote:

your examples are all completely incorrect anyway "incorrect" as to precisely what?

Keep reading the email mate. Incorrect as to your understanding of how the language works and at what point variables are defined.

The user MUST already know the exact identifier name

It's not an issue to need to know the name of the identifier. In fact, as you correctly pointed out, it's necessary. If I'm understanding it correctly, the value of the proposal is to make it easier to refactor (especially with variable renaming tools) without leaving behind string literals that no longer match the variable name.

I've run into this issue before, but it's been a relatively minor pain for me personally. So I can see some use for the proposal, though I suspect it would see most of it's use in tooling. On the other hand, it might add unnecessary complexity to the language, which should be avoided. Overall I'm very mildly supportive.

That leaves the use case of getting ALL of the names of the identifiers in the current scope

I have not seen anyone proposing this, so there's no reason to criticize it yet.

Obligatory disclaimer: not a TC39 member, no decision making power or influence on process On Jun 17 2019, at 2:42 pm, guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

The user MUST already know the exact identifier name or an error will be thrown for the original proposal and additional use case for nameof

const x = nameof y; // "y" const y = 1; making the need for nameof moot given that the user cannot then rationally state that the identifier as a string will somehow be mispelled if they are able to write the exact name of the identifer at nameof 100% of the time.

That leaves the use case of getting ALL of the names of the identifiers in the current scope

// NAMEOF is always dynamic list of let, const declarations in current scope console.log(NAMEOF); // ["x", "y"]; [{name:"x", line:5}, {name:"y", line:7}] // should resolve be in the list even if not declared using const or let? await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000)));

const x = nameof y await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000)));

const y = 1;

without having to already know the name of the identifiers, as is required by the original proposal, which essentially negates itself as the string literal 'y' is briefer than nameof y.

On Mon, Jun 17, 2019 at 4:19 AM Frederick Stark <coagmano at gmail.com<mailto:coagmano at gmail.com>> wrote:

guest271314, your examples are all completely incorrect anyway since all variable declarations (including let and const) are hoisted to the top of the scope, so when nameof y is evaluated, y is already declared in the scope.

The special behaviour introduced with let and const is that they set up a "Temporal Dead Zone" where attempts to set or get their value before the line where they are declared in code throws an exception. Since nameof doesn't care about the value, only the name of the variable, it would not need to throw an exception. Of course, were this proposal to be taken seriously, it could be specced either way

On Jun 17 2019, at 10:15 am, guest271314 <guest271314 at gmail.com<mailto:guest271314 at gmail.com>> wrote:

  • If y is directly visible in scope and is neither a parameter or

destructured binding, nameof y should just evaluate to "y". This should be agnostic to whether the binding has been declared yet, so in your example, x should be set to "y".

The 1st question at esdiscuss.org/topic/what-do-you-think-about-a-c-6-like-nameof-expression-for#content-33nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fesdiscuss.org%2Ftopic%2Fwhat-do-you-think-about-a-c-6-like-nameof-expression-for%23content-33&data=02|01|ron.buckton%40microsoft.com|cbc2c8f5e9614533e30e08d6f2e594ef|72f988bf86f141af91ab2d7cd011db47|1|0|636963465244030598&sdata=0jx0f3hXTqN3gfvuWWDh1BiuomZfI3eDdGXetyWSOtk%3D&reserved=0 remains:

Without having composed or previously read the source code, at line 1 adjacent to nameof how does the user know that there will be later declared variable named y?

On Sun, Jun 16, 2019 at 7:04 AM Isiah Meadows <isiahmeadows at gmail.com<mailto:isiahmeadows at gmail.com>> wrote:

Here's my opinion:

  • If y is directly visible in scope and is neither a parameter or destructured binding, nameof y should just evaluate to "y". This should be agnostic to whether the binding has been declared yet, so in your example, x should be set to "y".
  • If y is entirely undeclared, it should be a runtime ReferenceError in the same way it is when accessing undefined globals. So in your second example, I'd expect it to throw before even attempting assignment

Isiah Meadows contact at isiahmeadows.com<mailto:contact at isiahmeadows.com>

www.isiahmeadows.comnam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.isiahmeadows.com&data=02|01|ron.buckton%40microsoft.com|cbc2c8f5e9614533e30e08d6f2e594ef|72f988bf86f141af91ab2d7cd011db47|1|0|636963465244040592&sdata=ncNlzUB9%2FRJmg7%2Bt1vAM4UtxeAMm62ditqH%2BJh2f2kQ%3D&reserved=0

# guest271314 (6 years ago)

You have ignored the context from Jordan’s email (emphasis added):

again, Object.keys({ y })[0] will give you the string y, and will survive refactoring tools. you can even do function nameof(obj) { return Object.keys(obj)[0]; } and then nameof({ y }).

No, did not ignore the context of the email.

Simply have no reference point for relying on an external tool, that is, essentially a text editor, to write and dynamically "refactor" code. Here, the code will be tested outside of the text editor in short order once composed.

Was able to rename text at Mousepad and record the entire process within 20 seconds without needing to use nameof and without encountering any issues such as mispelling the variable name or the text editor trying to independently determine what the words am typing mean. The text editor is just - a text editor.

Perhaps other JavaScript users who rely on "refactoring tools" and "rename refactoring" in an IDE can relate. Not able to gather the significance of nameof here - as in each case the user has to write the name of the variable anyway. To each their own.

VSCode is a popular editor that supports JavaScript and is a refactoring tool. Rename refactoring was the subject I was responding to.

Was not previously aware or did not realize that the individual choice to use a particular text editor was a substantial reason to ask for change to the entire JavaScript language in order for specific users to be able to interact with an entirely different language.

If VSCode is particularly "popular" why cannot VSCode be specified and implemented by and for the users who rely on the text editor to interpret what the users' intent is when writing code?

In that case mkvmerge should be specified as a JavaScript method. webm is a "popular" (cannot help but to recollect "Popularity" brendaneich.com/2008/04/popularity) media container (that W3C's MediaRecorder implemented at browsers outputs) that is a subset of the Matroska container, where if that method were specified in JavaScript a user would be able to do mkvmerge({w: true, o: "int_all.webm": i: ["int.webm", "int1.webm", ...."intN.webm"]}) instead of $ mkvmerge -w -o int_all.webm int.webm + int1.webm (with duration set) at terminal.

# Isiah Meadows (6 years ago)

Because the declaration itself is hoisted. The TDZ only delays initialization, not declaration.

  • For var, the declaration is hoisted and it's automatically initialized to undefined before executing any body code.
  • For function foo() { ... }, the declaration is hoisted and the value is automatically initialized to a new function object encapsulating the function's body before executing any body code.
  • For all other types, the declaration is hoisted, but it is not possible to initialize it yet. It's initialized to undefined for let value; when that statement is executed, the relevant function object for class Foo, the RHS value for let value = expr/const value = expr, and so on. (Most of the complexity is in destructured bindings and default parameters, but it's not black magic, I promise.)
  • Keep in mind it's possible to get a reference to an uninitialized variable, even though it's not possible to access any value yet.

This mechanism already exists today, and nameof would just leverage that mechanism. The static value would be computed after the variable would have been linked (either at the global scope or after the declaration exists), and only after falling back to the global scope would the value fall back to a dynamic lookup and test.


Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# Isiah Meadows (6 years ago)

I get yet again that the forest here is being missed for the trees.

@guest271314 This isn't specific to any one IDE, and isn't even specific to static tools. As mentioned before, this has applicability to assertion libraries (like a userland version of Power Assert) as well as other things. It's almost exclusively just quality-of-life improvements to developers, but it's not specific to IDEs or even static tooling.


Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com

# guest271314 (6 years ago)

The current proposal is redundant. The user has to already know and write the exact name of the variable, or try to guess the variable name to not, or to, catch an error that includes the name of the identifier as a string. Why should the user have to already know and write the variable as a literal? If the use case is for an assertion, the only way the test could fail is if the developer intentionally wrote the incorrect variable identifer. How can the user know know the exact identifier execpt for writing and reading the code before using nameof without an error being thrown? If that feature is valuable to users of JavaScript by all means write that definition.

Extending the original proposal with the ability for the user to use nameof to get list of all varibales declared using const and let, class, var, et al., without having to already know and write the exact variable name, that is, when called without an adjacent exact variable identifier, e.g., const nameofall = nameof *; // ["y", "x"] which can also include line number as well, would not be redundant, and would also benefit users of JavaScript directly where defining the feature would provide values that are not currently possible (without previously knowing and writing the exact name of the variable identifier, or guessing the names of the identifiers, which should be also already be possible).

# Frederick Stark (6 years ago)

You've already made this point, so you're not adding anything new to the discussion now. Especially since your point seems to be "I don't understand" and "it won't help me personally" It's time to take a step back and allow others to discuss. If a formal proposal eventuates, you can continue to make your points there

# guest271314 (6 years ago)

Especially since your point seems to be "I don't understand"

Don't make up stories.

and "it won't help me personally"

Did not state that either.

It's time to take a step back

Not sure what you mean.

# guest271314 (6 years ago)

FWIW a start to nameofall using RegExp gist.github.com/guest271314/daa1c6455ec8a2b6b89aff245e95c615

const nameofall = /((const|let)\s+)\w+(?=\s+(=|in|of))|class\s+\w+(?=\s)/gi;

TODO: handle destructuring assignment, default values, shorthand assignments, e.g.,

const [{
  a = 1,
  b = 2
  }, cd] = [...[source]];

Usage: sourceCode.match(nameofall); // ["const x", "let z", "class G"]