Proposal: Symbol Linked to `typeof`
Let's restrict custom typeof
values to just symbols - objects are
unnecessarily weighty, strings would break a lot of code, and other
primitives are generally useless.
A property sounds compelling, and I feel like I saw it suggested a while back (forget where) something similar by a TC39 person.
I could definitely see usage of this when using custom Constructors. But this could confuse current code of JS:
function A(B, C) {
if(typeof B === 'string') // ...
}
A({[Symbol.typeof]: 'string'})
This would make old code updated to use not only typeof B === 'string'
, but also B instanceof String
to secure.
Well, I don't see why someone would do this for fun, but I think that someone would still use that.
I would definitely would like this feature, but there are some downsides.
On Sat, Jan 12, 2019 at 8:19 AM Randy Buchholz <work at randybuchholz.com>
wrote:
(Hi all, new to group)
Some of the Well Known Symbols are linked to standard functions – Symbol.toStringTag - A string value used for the default description of an object. Used by Object.prototype.toString().
When I have a Class instance (say,
const flow = new Flow()
, the debugger showsflow = Flow {
.But when I do
console.log( typeof flow)
the output isobject
.I assume changing basic behavior
typeof
would be breaking, but extending it through a symbol would be useful.
Symbol.typeofTag
of justSymbol.typeof
Invoking
typeof
on an object with this symbol would return “user-typed” information.
can't you just use the constructor name when needing more detail?
var a = new Date(); a.constructor.name "Date"
.constructor
is unreliable, and can be easily forged - of course,
Symbol.typeof
would create the same unreliability with one of the few
truly reliable operators in the language.
My thought was Symbol.typeof could improve both reliability and flexibility. It could be abused, but no more than Symbol.toStringTag. My use case is putting classes into “namespaces”. With [Symbol.typeof] = “Collections.Lists.LinkedList”, I can get the qualified type of the object. I can also use this in my IDE to keep my classes organized if I write tools to help me. Since imports use paths, if I move a file refactoring can be painful. With an IDE extension, I can trigger an event when I move a file to prompt “Update all imports?”. It can parse my project and update all imports to point to the right place.
From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of Jordan Harband
Sent: Tuesday, January 15, 2019 3:36 PM To: J Decker <d3ck0r at gmail.com>
Cc: es-discuss at mozilla.org
Subject: Re: Proposal: Symbol Linked to typeof
.constructor
is unreliable, and can be easily forged - of course, Symbol.typeof
would create the same unreliability with one of the few truly reliable operators in the language.
On Tue, Jan 15, 2019 at 12:38 PM J Decker <d3ck0r at gmail.com<mailto:d3ck0r at gmail.com>> wrote:
On Sat, Jan 12, 2019 at 8:19 AM Randy Buchholz <work at randybuchholz.com<mailto:work at randybuchholz.com>> wrote: (Hi all, new to group)
Some of the Well Known Symbols are linked to standard functions – Symbol.toStringTag - A string value used for the default description of an object. Used by Object.prototype.toString().
When I have a Class instance (say, const flow = new Flow()
, the debugger shows flow = Flow {
.
But when I do console.log( typeof flow)
the output is object
.
I assume changing basic behavior typeof
would be breaking, but extending it through a symbol would be useful.
Symbol.typeofTag
of just Symbol.typeof
Invoking typeof
on an object with this symbol would return “user-typed” information.
can't you just use the constructor name when needing more detail?
var a = new Date(); a.constructor.namea.constructor.name "Date"
(Posting Question) What is the preferred format/approach for highlighting code in posts?
Symbol.toStringTag can be used for this purpose now (and it already
unfortunately destroyed the reliability of
Object.prototype.toString.call
).
Right. Misappropriating a symbol corrupts its intent. As ES moves in a more towards a more "class-ish" feel, and people start writing more classes, a type/namespace system isn't far behind. Implementing some symbols to support this helps drive some standard approaches and discourages symbol misappropriation.
I don't think string namespaced names are the right feature here
Namespaces are intended mainly to avoid conflicts with names when sharing a global scope (like when using classpath in Java, or libs in C++) Javascript already solves this problems with modules, you can always guard your code with instanceof and the right instance of your class, you don't need "qualified names"
// flow.js
export class Flow {
}
// main.js
import { Flow } from './flow.js'; // we don't need namespaces, a "file
path" already resolves conflicts for us
const doSomething = (obj) => {
if (obj instanceof Flow) {
// ...
}
}
You can also customize the instanceof operation with Symbol.hasInstance
class Flow {
// Normally you would check the minimum contract required to any guard work
// Probably bad idea to override in most of the cases
static [Symbol.hasInstance](obj) {
return '_flow' in obj;
}
}
// Note that the control is inverse to your proposal the Class
determines if a value is instance (this why it's static)
// Without altering `Flow[Symbol.hasInstance]` just expected objects
will pass the check in `doSomething`
doSomething({}); // doesn't work
doSomething({ __proto__: Flow.prototype }); // doesn't work
doSomething({ _flow: undefined }); // actually works
~string qualified names are so 20th century~
michaelficarra/proposal-first-class-protocols may be relevant.
@Augusto Moura, I like the approach using hasInstance
.
It may be just me, but having your software architecture hardcoded to your filesystem (even with logical roots) feels shaky. (and so 1970’s 😊). Namespaces serve the purpose you stated at compile/runtime, but also serve as a form of human readable GUID for classes at design time, and allow creating a logical hierarchy independent of storage. This could be helpful for things like “object servers”/DI approaches. If I expose a service to deliver ES Classes, I don’t want users to know or depend on how I store them. ES is awesomely dynamic in every way except the hardcoded paths. Really, underlying the proposal is wanting to uniquely identify my classes with a token. As much for design-time as run-time. Currently, I expose a static GUID in all of my classes.
The module system is not filesystem based, but URL based, that's a lot of differences between the two, URLs are designed to be unique and be storage/protocol agnostic in most networks. Others languages are following similar paths, Go for example even allows you to import entire github projects directly in source code, Deno (a experimental Node-like platform, made by the Node former creator) follows the same direction. In a distributed world, URLs work really good as truly Global Unique Identifiers
In my opinion there's no better way to uniquely identifying than comparing it with the actual reference. But if you want a qualified name so badly, the only way I know is writing them manually, maybe you could use some external tool to automate this step, something like jscodeshift or a babel plugin. You could use decorators for runtime injection metadata (probably a parameterized namespace name)
const rootNamespace = 'com.foo'
const qualifiedName = (...namespaces) => (clazz) => {
const namespacesJoined = namespaces.join('.');
clazz.qualifiedName = rootNamespace + (namespacesJoined ? '.' + namespacesJoined : '') + '.' + clazz.name;
};
@qualifiedName('domain', 'package')
class Foo {
}
console.assert(Foo.qualifiedName === 'com.foo.domain.package.Foo')
Your Absolutely right! My mistake.
(Hi all, new to group)
Some of the Well Known Symbols are linked to standard functions - Symbol.toStringTag - A string value used for the default description of an object. Used by Object.prototype.toString().
When I have a Class instance (say,
const flow = new Flow()
, the debugger showsflow = Flow {
. But when I doconsole.log( typeof flow)
the output isobject
.I assume changing basic behavior
typeof
would be breaking, but extending it through a symbol would be useful.Symbol.typeofTag
of justSymbol.typeof
Invoking
typeof
on an object with this symbol would return "user-typed" information.(Posting Question) What is the preferred format/approach for highlighting code in posts?