-
Notifications
You must be signed in to change notification settings - Fork 378
Description
I have suggested this approach in the past (#315 (comment)), but after a recent realization, I think it deserves its own discussion.
The reason for switching to symbols are as follows:
-
Two conflicting versions of Fantasy Land would automatically not try to interact with each other, because they would have two different symbols. More on this thought (before Symbols existed) here: Reference to a canonical module in values static-land#45 (comment).
-
Symbols can be used to mutate prototypes of built-ins without stepping on anyone's toes. It seems to me that this is how first class protocols are implemented under-the-hood, and so by using symbols, we are taking a first step towards First-Class Protocols #291. It would allow a library to extend built-in prototypes with Fantasy-Land methods, rather than implementing support for built-in types at the dispatcher level.
-
Last but not least, my recent realization: Using strings means that code which uses Fantasy Land is vulnerable to the exact same problem that Promise-based code is vulnerable to. I have created a write-up about this vulnerability here: Add "then" to strings which may be used elsewhere minimaxir/big-list-of-naughty-strings#159.
In summary, code that creates StrMaps like
{ [userInput]: AnyFunction }
and passes it to a fantasy-land compliantmap
implementation such as Ramda'smap
or Sanctuary'smap
with the intent of mapping over the values, will behave differently if the user passesfantasy-land/map
as input. The same goes of course for all other algebras and all implementations of those that might get mixed with user-input.Using symbols would remove this vulnerability, as users have no way to pass symbols into a typical application from the outside.
Reasons I see against using symbols:
-
Managing compatibility between libraries might become more difficult. Let's say Fantasy Land 5.0.0 adopts symbols. Now ADT library authors such as myself would have to add
fantasy-land
as a dependency in order to use the "correct" symbols for interoperability with a dispatcher lib. Then later when Fantasy Land 5.1.0 comes out with some new algebra, the dispatcher library might upgrade to it whilst the ADT library doesn't.At this point it might happen that a package manager such as
npm
installs two distinct versions of Fantasy Land in a project which uses both the dispatcher lib and the ADT lib. Those two distinct installations of Fantasy Land will provide two distinct symbols, and as such, the dispatcher lib will no longer be able to interact with the ADT. This can be avoided in some ways (having Fantasy Land as a peer dependency, or using some automated deduplication strategies), but either way it's not as easy as it was with Strings. -
It might take some time before symbols see full adoption. It's a hard-reset for the Fantasy Land community, and for some transition period, libraries would probably need to provide both strings and symbols.
Symbol.for
Instead of using the distinct Symbol
constructor, Fantasy Land could use Symbol.for('fantasy-land/map')
. Library authors would not need to rely on a fantasy-land
package in order to provide interoperability. This would remove benefit 1
and problem 1
from the pros and cons listed above, leaving us with benefit 2
and 3
.