-
-
Notifications
You must be signed in to change notification settings - Fork 504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Symbol.species? #156
Comments
I'm not familiar with Is there a good document anywhere on |
The mozilla doc is pretty good and links to the ECMA spec: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/species Basically, the trick here is that Symbol.species is only defined as a static (property on the constructor), so we are free to use it for other purposes, but you could also attach namespaced properties on the static species if you so wish I think. |
Not sure how the Symbol.species may be used but we must consider its adoption (the IE story does not look that great). |
Hmm, good point. There's a polyfill for IE, but maybe we should find a different spec that doesn't rely on Symbol. As far as I can tell, Microsoft doesn't plan on supporting a bunch of new technologies with IE. I've already decided not to support Safari for any of my projects for similar reasons (people just get a page telling them to get a real browser), but I realize this is not an option for everyone. |
If It's one thing for an application to decide to drop support for Microsoft stuff, quite another for a library, especially since developers might end up finding out about it after they've deployed it in a production environment and it breaks for users, because honestly, we aren't reading the freaking manual most of the time 😀 |
Given that TypeScript will include support for indexing via symbols (microsoft/TypeScript#15473), a viable (and less spec-violating) approach would be to define a custom symbol const type = Symbol("type");
type _ = any;
interface TypeTag<U, A> {
readonly kind: U;
readonly type: A;
}
interface App<U, A> {
[type]: TypeTag<U, A>
}
abstract class Functor<F> {
abstract map<A, B>(fa: App<F, A>, f: (a: A) => B): App<F, B>;
}
// Using _ as any makes clear our intentions about App:
// App<Container<_>, T> reads as "apply T to the partial application in Container<_>"
class Container<T> implements App<Container<_>, T> {
[type]: TypeTag<Container<_>, T>
constructor(public readonly get: T) {
}
}
// In Scala this would be `extends Functor[Box[_]]` to denote higher-kind application
class ContainerFunctor extends Functor<Container<_>> {
map<A, B>(container: App<Container<_>, A>, f: (a: A) => B): Container<B> {
// Here we'll cast the type application to a concrete U<A> type
const a = (container as Container<A>).get;
return new Container(f(a));
}
}
const f = new ContainerFunctor();
f.map(new Container(1), a => a); This would still have the advantage of preventing access to internal properties, tooling would ignore them and, symbols being unique, would prevent naming or semantic conflicts with other libraries and conventions. Symbols are also well-supported in all modern browsers if we're not relying on a certain builtin symbol like |
Good idea! Would we be better off defining a global system with a namespaced name, so we don't need a dependency library? const type = Symbol.for("fantasy-land/type"); Not sure which namespace would be best, so I just picked fantasy-land, because it's popular. That one has the advantage of not needing a dependency to provide the symbol, as well as being unique enough. |
HKT encoding is now frozen (v1.0.0) |
Why not use
Comparisons would be faster, i.e. in line 126 would be |
@rui-atg Perhaps because TypeScript cannot do type narrowing based on symbols. |
A more canonical way to do branding in modern JavaScript is Symbol.species. Javascript only defines Symbol.species when it appears as a static in a class (or as a property on a constructor function, which is the same thing). Putting it on the instance is not defined, but allowed. Basically, this is valid JavaScript code:
No more underscores (uses namespacing with "fp-ts/" instead) and no polluting the object. Advantage is that symbols are not enumerable at runtime, and they don't show up in
keyof
at compile time, while still providing their function in constraints. the namespacing with "fp-ts" is optional of course, but I expect other libraries will start using Symbol.species in the future and as fantasy-land indicated, "namespace/" is kind of the canonical way to avoid collisions.The text was updated successfully, but these errors were encountered: