Stdlib organization with re-export idiom
metagn opened this issue · comments
Based off of #497 (comment)
A common idiom in Nimble packages is to have submodules for individual features of the package, then a main module that re-exports them all (i.e. import foo/[a, b, c]
== import foo
). This means users both can pick only the features they need, and don't have to worry about which features they might need if they just import the main module.
Applying this idiom in the standard library has already been discussed for os
, times
, json
etc. but there might be some other existing applications that are easier to implement and less likely to cause breakages.
1. Sugar
The sugar
module currently consists of the following independent definitions:
=>
and->
dump
anddumpToString
capture
dup
(depends onstd/private/underscored_calls
which is also used bystd/with
)collect
I propose these are put in their own submodules and then re-exported in sugar, with respectively the following module names:
std/sugar/arrows
orstd/sugar/lambdas
? Unsurestd/sugar/dump
std/sugar/capture
std/sugar/dup
std/sugar/collect
We could also drop the sugar/
and just put these directly in std/
as they do not conflict with other modules. However this could be confusing, people could import std/[collect, dup, sugar]
and not realize.
I also think the following, existing modules should be re-exported in sugar:
std/with
std/enumerate
- Maybe
std/decls
? - Maybe
std/wrapnils
?
The point of "sugar" is that it's lazy/convenient, and the most convenient thing would be to have a unified import for all of these. But also we shouldn't have to import everything just for collect
or dump
or arrows etc.
2. Strings
strutils
contains a lot of important definitions for strings that aren't just "utilities", and so it is extremely popular along with strformat
. On top of strutils, there is strmisc
which is tiny and honestly isn't that disconnected from the rest of strutils.
While it might be nice to split strutils
for specific things people might need, it would be a huge effort and there is the nimrtl
stuff that maybe shouldn't be disturbed. However there are some minor things that could be done:
- Sets of characters, i.e. AllChars, Letters, Digits, Whitespace etc. along with procs like
allCharsInSet
could go in a separate module and get re-exported. Sometimes modules will import strutils just for these (example beingwordwrap
). - The outplaced
parseutils
wrappers could go inparseutils
or a separate module and get re-exported/wrapped again. (alsofromHex
andparseHexInt
have the same implementation yet do not mention each other in documentation) std/formatfloat
is unrelated tostrutils.formatFloat
. We could rename the currentstd/formatfloat
tostd/floatdollar
or something, make a newstd/formatfloat
with the formatFloat procs and re-exportedfloatdollar
, then we can re-export that in strutils.formatSize
is out of place along with its enumBinaryFormatMode
. It could have its own module, and may or may not be re-exported.
To make them easier to discover, we could also re-export cstrutils
, strbasics
somewhere, and stuff like editdistance
, wordwrap
in strmisc
. There are also modules like encodings
and unicode
that people aren't aware of sometimes and ask about, but these might be too big to re-export.
This goes into the right direction but the import/export idiom is not without its problems for discoverability, esp for newcomers.
Also, I still don't know why e.g. cmpIgnoreCase
should be connected to editDistance
via a single import std / strings
. editDistance
is not even useful when you think it would be. For typo corrections it typically produces poor results.
Well, it shouldn't. The name std/strings
is too broad, it's misleading if it doesn't export the infinite string stuff we have.
Classifications like "miscellaneous string algorithms in the standard library", which to me is what strmisc
implies, are finite and unlikely to intersect with anything else. Most stuff already in the standard library like cmpIgnoreCase
are going to be fundamental enough that they don't belong there, but rarer stuff like editdistance would belong IMO. Brushing them off as "miscellaneous" also implies they aren't perfect implementations either. However currently strmisc
consists of direct proc definitions, so maybe it's not ready to have re-exports (expandTabs
and partition
could respectively go in std/indents
and std/strsplit
if strutils
is split up).
One major problem with reexports imo is currently that the docs for reexported items don't show up, they just get listed in an "Exports" section (see here for an example). I think this should definitely be fixed before we do something like this. Apart from that, I like the idea of using submodules in the standard library, although I'm not sure about having a submodule for each macro in std/sugar
...
I thought the sugar
part would be the obvious one. IMO it's better than putting all the random macros in the same module. We could maybe group them together, like =>
and capture
both have to do with lambdas, with
and dup
are pretty similar, etc.
I think there is an RFC to overhaul the doc page structure that involves getting rid of the proc/template/iterator etc sections, maybe along with that we could add an "Exported" section to the bottom that shows the docs of all the exported symbols.