Sanctuary depends on sanctuary-def, as specified in __package.json__. Furthermore, Sanctuary is only compatible with certain versions of sanctuary-def. @codedmart recently brought it to my attention on Gitter that the example for create does not work if one uses the current version of Sanctuary (v0.11.1) with the current version of sanctuary-def (v0.9.0).
There are (at least) two things we should consider:
[email protected] always depends on and works with [email protected].Could we use peerDependencies to express the constraint?
"dependencies": {
"sanctuary-def": "0.9.0",
"sanctuary-type-classes": "2.0.1",
"sanctuary-type-identifiers": "1.0.0"
},
"peerDependencies": {
"sanctuary-def": "0.9.0"
}
versioning the two packages such that
[email protected]always depends on and works with[email protected]
This could be a handy indicator, but might also be a hassle to maintain and assure.
Could we use
peerDependenciesto express the constraint?
I've never seen peerDependencies used like that, though I haven't come across the situation where a package is both a dependency and a plugin to another package. I guess it might win us an automatic warning when the user tries to use an incompatible def, but I think it's all a bit messy. It relates the concerns I expressed here.
The problem, I think, is that multiple parties are creating black-box data structures (type definitions) using sanctuary-def and multiple parties need to interpret (call def on) those structures using sanctuary-def. Maybe it's possible for the future to ship the interpreter with "batteries included", eg:
const sanctuary = require('sanctuary');
const $ = require('sanctuary-def');
const env = $.env.concat(sanctuary.env).concat(myEnv);
const def = TYPE_CHECKING ? $.createTypecheckedDef(env) : $.def;
const S = sanctuary.create(def);
sanctuary would have to have a Peer Dependency on sanctuary-def, but not direct dependency. It's compatibility with def would only change if the type signature of def() changes, but not when the internal data structures change. Maybe It's a bad idea. Might be one for Ideas about env ;)
Ah I just realized what the flaw in my idea above is: In order to provide an env, we would still need sanctuary-def, and we'd still have the "multiple parties with incompatible data-structures"-problem.
But it does seem to me like removing sanctuary-def from dependencies and keeping it as only a peer-dependency would reduce complexity. If all these parties would do the same thing, you can be sure that the data structures will be compatible.
But it does seem to me like removing
sanctuary-deffrom dependencies and keeping it as only a peer-dependency would reduce complexity.
I agree. const S = sanctuary.create(def); seems very nice to me! Let's seriously consider this change once we get v0.12.0 out the door. :)
Here's what I think we should do:
sanctuary into small modules, each with a peer dependency on sanctuary-def (and possibly sanctuary-type-identifiers and other shared dependencies):sanctuary-either to contain the Either type, its Repr, and associated functionssanctuary-maybe to contain the Maybe type, its Repr, and associated functionssanctuary-list for list related functionssanctuary-string for string related functionssanctuary-strmap for the StrMap type, its Repr, and related functionssanctuary-prelude library which takes from each of the above libs to provide a set of common tools.sanctuary library will have a single function. To load sanctuary-prelude and the shared peer dependencies like sanctuary-def, and instantiate the prelude with a default def.People who want an out-of-the-box experience will use sanctuary, people who want a customized one will use sanctuary-prelude, people who want only parts of the functionality will assemble their own utility belt from the available underlying libs.
This tackles several problems:
sanctuary-maybe-type, sanctuary-maybe-from-nullable. This package structure is "composable" all the way down to sanctuary.require('sanctuary') directly, which defeats the point of disabling type-checking": Now, I will depend only on sanctuary-prelude, and provide my own assembly which they have to use.sanctuary-def is not compatible with yours": Since all packages but sanctuary have it as a peer dependency, they will all use the same version and NPM will show it when one is not compatible and should be down or upgraded.ENV_X to determine whether to check types": The community is now free to provide many Sanctuary assemblies, since it's very easy to set up. Just depend on the compatible sanctuary-* packages and export create(myDef).Is it UnaryType that breaks things currently?
I really don't know the internals of sanctuary so I have no idea what is possible but I assume that each of those packages would need sanctuary-def (78 kb) and sanctuary-type-classes (45kb). Right now sanctuary is 100kb, let's say sanctuary-maybe would me 15kb. Would it make sense to have a separate package of 15kb with 123kb of dependencies? In that case, me as a user, I would prefer to download an es6 modularized sanctuary and tree shake it myself. Other option is to ask if you are downloading a single package probably you are working on a small project and you would not need type checking, so remove type checking on individual packages -if possible.
Most helpful comment
Here's what I think we should do:
sanctuaryinto small modules, each with a peer dependency onsanctuary-def(and possiblysanctuary-type-identifiersand other shared dependencies):sanctuary-eitherto contain the Either type, its Repr, and associated functionssanctuary-maybeto contain the Maybe type, its Repr, and associated functionssanctuary-listfor list related functionssanctuary-stringfor string related functionssanctuary-strmapfor the StrMap type, its Repr, and related functionssanctuary-preludelibrary which takes from each of the above libs to provide a set of common tools.sanctuarylibrary will have a single function. To loadsanctuary-preludeand the shared peer dependencies likesanctuary-def, and instantiate the prelude with a defaultdef.People who want an out-of-the-box experience will use
sanctuary, people who want a customized one will usesanctuary-prelude, people who want only parts of the functionality will assemble their own utility belt from the available underlying libs.This tackles several problems:
sanctuary-maybe-type,sanctuary-maybe-from-nullable. This package structure is "composable" all the way down tosanctuary.require('sanctuary')directly, which defeats the point of disabling type-checking": Now, I will depend only onsanctuary-prelude, and provide my own assembly which they have to use.sanctuary-defis not compatible with yours": Since all packages butsanctuaryhave it as a peer dependency, they will all use the same version and NPM will show it when one is not compatible and should be down or upgraded.ENV_Xto determine whether to check types": The community is now free to provide many Sanctuary assemblies, since it's very easy to set up. Just depend on the compatiblesanctuary-*packages andexport create(myDef).