What do you think about a C# 6 like nameof() expression for
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:
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
)?
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
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?
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.
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?
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.
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).
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.
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
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 callinglet 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 hasnameof
function.Minification.
If your code to be minimized be prepared that variable names will also change.
(just a possibility) Minimizer can have option to replace
nameof(someVar)
with result ofnameof
function.What if user already has
nameof
function.
To maintain status quo we can user
nameof
function having priority over newly introduced language feature.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
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?
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?
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.
Interesting.
y
would be able to be evaluated beforey
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
nameof whatever
→ Object.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.
nameof whatever
→Object.keys({ whatever })[0]
, but I'm a bit confused why it'd be better to typenameof foo
in code, rather than'foo'
- if you changefoo
tobar
, 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 whatever
→ Object.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?
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?
Fri, 14 jun 2019 - 18:29, Jordan Harband <ljharb at gmail.com> wrote:
nameof whatever
→Object.keys({ whatever })[0]
, but I'm a bit confused why it'd be better to typenameof foo
in code, rather than'foo'
- if you changefoo
tobar
, 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);
}
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 whatever
→Object.keys({ whatever })[0]
, but I'm a bit confused why it'd be better to typenameof foo
in code, rather than'foo'
- if you changefoo
tobar
, 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 whatever
→ Object.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?
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 functionsetValue
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?
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 the
nameoffunctionality 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 for
nameof``` 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 whatever
→Object.keys({ whatever })[0]
, but I'm a bit confused why it'd be better to typenameof foo
in code, rather than'foo'
- if you changefoo
tobar
, 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 whatever
→ Object.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?
It doesn’t matter what the value of ‘y’ is, just what the lexical name of
y
is.nameof
wouldn’t refer toy
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
}
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 toy
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 the
nameoffunctionality 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 for
nameof``` 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 whatever
→Object.keys({ whatever })[0]
, but I'm a bit confused why it'd be better to typenameof foo
in code, rather than'foo'
- if you changefoo
tobar
, 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 whatever
→ Object.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?
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?
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:
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
.
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:
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;
?
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 becausenameof
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:
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;
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).
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;
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 runtimeReferenceError
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
- 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
?
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
your examples are all completely incorrect anyway
"incorrect" as to precisely what?
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)) {... }
.
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
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.
Object.keys({ y })[0]
will give you the stringy
, 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 runtimeReferenceError
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
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?
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 stringy
, and will survive refactoring tools. you can even dofunction nameof(obj) { return Object.keys(obj)[0]; }
and thennameof({ 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?
… 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 runtimeReferenceError
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
You have ignored the context from Jordan’s email (emphasis added):
again,
Object.keys({ y })[0]
will give you the stringy
, and will survive refactoring tools. you can even dofunction nameof(obj) { return Object.keys(obj)[0]; }
and thennameof({ 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
.
Because the declaration itself is hoisted. The TDZ only delays initialization, not declaration.
- For
var
, the declaration is hoisted and it's automatically initialized toundefined
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
forlet value;
when that statement is executed, the relevant function object forclass Foo
, the RHS value forlet 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
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
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).
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
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.
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"]
Can we revisit this issue?
In C# there is
nameof
, in Swift you can do the same by callingLet'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 hasnameof
function.Minification.
If your code to be minimized be prepared that variable names will also change.
(just a possibility) Minimizer can have option to replace
nameof(someVar)
with result ofnameof
function.What if user already has
nameof
function.To maintain status quo we can user
nameof
function having priority over newly introduced language feature.OR we can use
typeof
syntax, e.g.nameof msg.userName
(// returns "userName" string)