-
Notifications
You must be signed in to change notification settings - Fork 23
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
one definition rule for defined
symbols: defined(foo)
requires declare(foo)
#269
Comments
Instead we can make docgen recognize top-level when statements that look like this: when defined(foo):
## Documentation for foo |
that doesn't help with defined symbol clashes. |
The same pattern could be detected and warned about with my proposal. This RFC is only really worthwhile combined with #181 IMO, but then again nothing prevents you from prepending your module/project name to your defines as we do already. So the aforementioned pattern combined with using a prefix already solves all problems that this RFC and #181 solve and doesn't require a new language construct ( EDIT: One advantage that this RFC has is that you will get a warning on typos like |
your proposal gives a new meaning to something that already has a (useful) meaning, eg: when defined(js):
## doc comment specific to js and furthermore is less searchable; using a dedicated API for that is better than conflating pre-existing syntax.
happy to bikeshed alternative names
yes, this is in fact common, thanks for reminding me to add that, it was also a motivating factor for this RFC;
it's not enforced, and is regularly abused including in nim repo, despite the fact we caution against it, see https://nim-lang.github.io/Nim/contributing.html#best-practices. Furthermore it doesn't solve all problems, eg it doesn't allow you to list/extract doc comments for those defined symbols, and doesn't help with prefix issue mentioned in #181 |
Another already existing functionality that provides the same advantages as this RFC, is We could promote their usage and allow |
good to point out # t11150b.nim
const foo1 {.booldefine.} = false
# main.nim
import t11150b
const foo1 {.booldefine.} = false IMO it should for same reasons as provided in this RFC.
# in system.nim
import std/system_defines
# in system_defines.nim
const
release {.booldefine.} = false ## doc comment
danger {.booldefine.} = false ## doc comment note that |
We can put const release {.booldefine.} = false directly into system since the const itself wouldn't be exported and we can make |
yes, no need for
that I don't understand. this RFC wouldn't make system special (which is often a bad idea). Here's what I have in mind, please suggest if you have a better idea: # in system.nim
const release {.booldefine.} = false
when defined(release): discard # ok
# under #181
when defined(system.release): discard # error: system.release not booldefined
const foo {.booldefine: "nim.foo".} = false
when defined(nim.foo): discard # ok
when defined(foo): discard # error: foo not booldefined |
Ah yeah, I was thinking of automatically scoping |
I use this idiom instead: const
debugOrc = defined(nimDebugOrc)
when debugOrc: ...
Typo-safe, uses an existing language feature that works well with Nim's scoping rules. |
Thinking about it, const release {.booldefine.} into declare release
const release = defined(release) which would also map better to .cfg files ( |
const debugOrc = defined(nimDebugOrc)
when debugOrc: ... this doesn't work.
|
(Of course it does work, I use it successfully.)
That's true but if we address this problem, we should also catch mistyped --defines on the command line. Which can be done rather easily: Remember all the
Libraries shouldn't use --define switches anyway, every switch creates a unique library version. |
@Araq it doesn't work reliably if you have {.undef.}, {.define.} anywhere in your code: const foo {.booldefine.} = false
proc main()=
echo (foo, defined(foo))
{.define(foo).}
echo (foo, defined(foo))
static: main() (true, false) # foo != defined(foo) And yes, those flags
yes, I thought about adding that too in the RFC, definitely doable and should be done.
nim relies on it so much because nothing else fits that use case yet (open config flag), so it's not surprising that other packages will too, following existing practices. It's broken though and will only get worse as more packages are added in the wild, which is why I'm trying to fix it in #269 and #181 to give it sane, scoped, typesafe semantics. The fact is that many nimble packages use their own Can you guess which defined comes from which package without looking at the title?
etc... I have 324 unique defined symbols in a small ~/.nimble_tmp/pkgs folder, and no idea how many clash, or which belongs to which, or which are typos like |
I believe we already have guidelines suggesting that authors name their defines according to their package, eg. I've been using this style since I started writing Nim. Coupled as it is with @Araq's technique above, it works fine. If defines are a problem, well, this isn't the fix. Scoping them just sweeps the issue under the rug and makes it even easier to fragment libraries and harder for them to share defines or inspect each other. |
We already have "scoped" defines, they are called However we should ensure that |
Closing in favor of #181 |
This proposal will make
defined
symbols self documenting (using doc comments ondeclare(foo)
)It provides a solution to the problem of clashes where 2 libraries use
defined(foo)
with 2 different meanings.It also helps by giving a warning when using a mistyped or nonexisting defined symbol:
when defined(rellease)
will now give aWarnDefinedUndeclared
under this proposal.it also helps for migrating code, when a defined symbol is renamed from
foo
tobar
(or whenfoo
is deprecated), we currently have no easy way to encourage users to change their code; under this proposal this becomes trivialproposal
This proposal adds type safety to
defined
statements, requiring each use ofdefined(foo)
to be preceded by a uniquedeclare(foo)
statement, in other words, adding "one definition rule" to defined statements.note that
declare(foo)
doesn't definefoo
, unlike{.define(foo).}
or-d:foo
on cmdline; it merely prevents getting a warning when usingwhen defined(foo)
or{.undef(foo).}
or{.define(foo).}
for legacy defines (eg: -d:danger, -d:release etc), these would be declared in system.nim as follows:
for defines in 3rd party packages, it's the same:
so this proposal is complimentary to #181 (ie both can be implemented and make sense together).
declared symbols would be exposed via an API and via docgen
currently we rely on manually generated list of defined symbols eg: https://nim-lang.github.io/Nim/nimc.html#additional-compilation-switches
Under this proposal we'd be able to have the declared symbols shown in docs in a new "declared defined symbols" category.
=> docgen would pickup the doc comment, as it would for other symbols
macros.nim would also allow listing all declared symbols for reflection purposes.
EDIT: note:
declare
can be bikesheddedan alternative could be
declareDefine
, or{.booldefine.}
as explained in #269 (comment)with same ODR rules as defined in this RFC.
The text was updated successfully, but these errors were encountered: