Skip to content
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

Split std/times #18378

Closed
wants to merge 5 commits into from
Closed

Split std/times #18378

wants to merge 5 commits into from

Conversation

konsumlamm
Copy link
Contributor

@konsumlamm konsumlamm commented Jun 28, 2021

Refs nim-lang/RFCs#55.

This PR splits off two modules from std/times, which are both reexported:

  • std/times/core contains core types and procs used by the other modules
  • std/times/durations contains the types and procs related to durations

I used the {.all.} pragma and importutils.privateAccess to be able to access internal definitions from the core and durations modules, that are needed by times, as I didn't want to create separate private modules that export everything and are then partly reexported.

The CI is currently failing, partly due to my use of std/importutils (cc @timotheecour), I'm investigating this. A part of the reason is that operators are redefined to not include overflow checks for the JS backend (since that's apparently broken), is that really necessary (shouldn't that either be handled in system or not at all)?

Add module `std/times/core`
Add module `std/times/durations`
Remove `{.raises: [Defect].}`
@timotheecour
Copy link
Member

timotheecour commented Jun 28, 2021

as the CI logs say:

2021-06-28T16:08:28.9585520Z /Users/runner/work/1/s/lib/std/importutils.nim(23, 41) Warning: unknown magic 'PrivateAccess' might crash the compiler [UnknownMagic]

PrivateAccess is only available for nim >= 1.5.1 so this can't be used during bootstrap unless csources_v1 gets updated to 1.6

Other than that, nothing against splitting std/times, but IMO we should build Durations on top of int128 instead of what we have (object: seconds: int64, nanosecond: NanosecondRange), as it'll make the math simpler and more efficient, avoiding having to use base-1M operations everywhere, refs:

@konsumlamm
Copy link
Contributor Author

PrivateAccess is only available for nim >= 1.5.1 so this can't be used during bootstrap unless csources_v1 gets updated to 1.6

Does that mean I shouldn't use PrivateAccess (which would make things a lot uglier imo) or wait for 1.6 with this PR?

Comment on lines -207 to -227
# This is really bad, but overflow checks are broken badly for
# ints on the JS backend. See #6752.
{.push overflowChecks: off.}
proc `*`(a, b: int64): int64 =
system.`*`(a, b)
proc `*`(a, b: int): int =
system.`*`(a, b)
proc `+`(a, b: int64): int64 =
system.`+`(a, b)
proc `+`(a, b: int): int =
system.`+`(a, b)
proc `-`(a, b: int64): int64 =
system.`-`(a, b)
proc `-`(a, b: int): int =
system.`-`(a, b)
proc inc(a: var int, b: int) =
system.inc(a, b)
proc inc(a: var int64, b: int) =
system.inc(a, b)
{.pop.}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to remove this for now, to make things easier. This still needs to be addressed somehow though, perhaps by disabling overflow checks for the JS backend in system?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would be addressed by timotheecour#762 (int128 which can be implemented on top of jsBigInt on js backend)

@@ -2067,7 +1673,7 @@ template formatValue*(result: var string; value: Time, specifier: string) =

proc parse*(input: string, f: TimeFormat, zone: Timezone = local(),
loc: DateTimeLocale = DefaultLocale): DateTime
{.raises: [TimeParseError, Defect].} =
Copy link
Member

@timotheecour timotheecour Jun 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #16724 (comment)
this requires csources_v1 >= 1.4.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that mean I should undo this change (also see #18378 (comment))?

Copy link
Member

@timotheecour timotheecour Jun 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unless you can figure out a way that works during bootstrap, I don't see another way.

you can test locally whether it works by building:

bin/nim_csources_a8a5241f9475099c823cfe1a5e0ca4022ac201ff c compiler/nim
bin/nim_csources_a8a5241f9475099c823cfe1a5e0ca4022ac201ff c koch

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I also can't use importutils.privateAccess/{.use.}?

Copy link
Member

@timotheecour timotheecour Jun 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean {.all.}, not {.use.} ? indeed. It can be used in code that's not used during compiler bootstrap or needs when defined(nimHasHintAll) or any recent such condsyms symbol if you can get away with custom implementation for the needed symbols during bootstrap

# Duration
#

const DurationZero* = Duration() ## \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any style guide still recommending ## \ ? if so they should be updated, it doesn't seem necessary (simpler = better)
as can be seen with:

nim doc -r main

const a1* = 10 ## \
  ## ok1
  ## ok2

const a2* = 10
  ## ok1
  ## ok2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I forgot to change that (times used this before, for some reason).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

separate cleanup PR welcome; better to separate non-controversial PRs from more difficult ones so that the non-controversial one gets merged fast and doesn't complicate the other one

@arnetheduck
Copy link
Contributor

While you're here: #17072

@timotheecour
Copy link
Member

While you're here: #17072

yes, but it can be done independently of this PR (either before or after)

@Araq
Copy link
Member

Araq commented Jun 28, 2021

So I also can't use importutils.privateAccess/{.use.}?

No, you can't and I don't see why it's necessary. Use proper layering instead.

@konsumlamm
Copy link
Contributor Author

konsumlamm commented Jun 28, 2021

So I also can't use importutils.privateAccess/{.use.}?

No, you can't and I don't see why it's necessary. Use proper layering instead.

The problem is that for example std/times needs access to the internal procs from std/times/durations. The only other way to do this (since afaik Nim as no "package-private" access modifier), that I can think of, is putting everything in some private module and then reexport part of that in std/times/durations, but that breaks the generated documentation, as it only shows a list of reexported symbols.

If there's another way to do this, please tell me (sorry if I'm missing something obvious).

@timotheecour
Copy link
Member

timotheecour commented Jun 28, 2021

but that breaks the generated documentation, as it only shows a list of reexported symbols.

this is a common problem with re-exports in similar cases, we could patch docgen to show docs for re-exported symbols (with an indication that it's a re-export); it's not critical though as nagivation in docs will still work so you can click the re-export and see its docs (even if it points to a private module). The important things to preserve are:

  • symbols should be transparently movable to another module via import+re-export (no change in semantics for client code)
  • docs are visible somehow in generated html (whether in re-exported module or private module), and no duplication happens in source code
  • once csources_v1 is upgraded to 1.6, this intermediate layer can disappear again (removing raises Defect only requires bootstrap >= 1.4)

The other point (regarding Duration as int128) is more tricky but important.

@Araq
Copy link
Member

Araq commented Jun 29, 2021

that I can think of, is putting everything in some private module and then reexport part of that in std/times/durations, but that breaks the generated documentation, as it only shows a list of reexported symbols.

That would be the proper way though. But yeah, considering that then the docs are more annoying to use, can't we leave times.nim alone instead please?

@Araq
Copy link
Member

Araq commented Jun 29, 2021

symbols should be transparently movable to another module via import+re-export (no change in semantics for client code)

IMHO re-exports are bad style and a last resort.

docs are visible somehow in generated html (whether in re-exported module or private module), and no duplication happens in source code

That mitigates the problems of re-exporting but avoiding re-exports is still the better solution.

once csources_v1 is upgraded to 1.6, this intermediate layer can disappear again (removing raises Defect only requires bootstrap >= 1.4)

There are no plans to update csources to 1.6 anytime soon btw, if we need to write new compiler in a compiler2 directory, so be it.

@timotheecour
Copy link
Member

if we need to write new compiler in a compiler2 directory, so be it.

not sure how that would help with bootstrap issues (including for building koch which depends on many things, but also for building compiler/nim).

As for docs + re-export, it's a solvable problem that only requires a targeted (docgen) patch. Besides the solvable docs problem, I'm not sure what are objective downsides of re-export (eg it doesn't give ambiguous symbol error since it's the same symbol)

@Araq
Copy link
Member

Araq commented Jun 29, 2021

Re-exports are bad because they add access paths to a symbol: You type module.foo and the compiler expands it to moduleB.foo in an error message, it's great. Re-exports are also usually used because Nim doesn't attach procs to types, Java and C# don't have re-exports.

@timotheecour
Copy link
Member

timotheecour commented Jun 29, 2021

Re-exports are bad because [...]
Java and C# don't have re-exports.

... but D, python3, swift, rust, js, typescript, etc even C++ modules and C's #include, all support re-export, and for good reason, it allows changing implementation without affecting client code, and layering the API.

Error messages and docs only require targeted fixes, eg keeping the mapping in some Table[PSym, PSym], similar to importModuleMap*: Table[int, int] # (module.id, module.id) from #18366, which works.

@arnetheduck
Copy link
Contributor

Not sure if they're bad or not, but re-exports are needed to get predictable behavior with generic code - the guideline we use is that if a public symbol uses a type declared in another module, that module should be reexported - it's the only way we've managed to alleviate unpredictable and surprising behavior (https://status-im.github.io/nim-style-guide/language.import.html) - also because in order to actually use the public symbols, you need those definitions anyway - ie Option is useless without get - specially with larger code-bases, it's somewhere between extremely tedious and impossible to get by without exports

@timotheecour
Copy link
Member

IMO a pre-requisite for a durations module is nim-lang/RFCs#399, so that we're not stuck with a bad design forever.

@stale
Copy link

stale bot commented Jul 30, 2022

This pull request has been automatically marked as stale because it has not had recent activity. If you think it is still a valid PR, please rebase it on the latest devel; otherwise it will be closed. Thank you for your contributions.

@stale stale bot added the stale Staled PR/issues; remove the label after fixing them label Jul 30, 2022
@konsumlamm
Copy link
Contributor Author

I don't think this is currently viable.

@konsumlamm konsumlamm closed this Jul 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale Staled PR/issues; remove the label after fixing them
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants