-
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
[compiler/pathutils] AbsoluteFile,AbsoluteDir,RelativeFile,RelativeDir
is too complicated
#71
Comments
type
Path* = distinct string is not good enough for the Nim compiler and so it's not typesafe enough for other code bases too. In particular, filenames and directories are completely different beasts.
That's not a problem, that's a feature, you need to validate/check your inputs.
Wrong, I cannot even compare filenames with paths, that's a feature too.
A filename is a |
|
It is a discussion of how to design a better |
now that there's a talk of starting to integrate compiler/pathutils inside ospaths to allow reusing its
relativeTo
inospaths
(as suggested here: nim-lang/Nim#8166 (comment)) it's time to look into design decisions more carefully.I actually had a WIP PR that moved things around to allow for that (see branch https://github.com/timotheecour/Nim/tree/pr_ospaths_pathutils [it's WIP]) but I don't like the resulting API's.
let me denote by
strongly typed paths
the types introduced in compiler/pathutils:Let's contrast this with following alternative, dubbed
simply typed paths
:IMO, distinguishing (what's more, at compile time) between these 4 variants doesn't pull its weight, and results in a lot of procs being duplicated. It's already the case in pathutils, and, if we apply same logic to rest of procs in ospaths, the problem is only gonna get worse.
problem 1: dealing with paths of unknown type
suppose an application deals with some paths of unknown origin (paths could be either absolute or relative, files or dirs) where we don't care which category these belong to; there's no simple way to express these in terms of the strongly typed paths, nor to use strongly typed API's ; this forces user code to be generic, which is "contagious", what would've started as non-generic code has to become generic, adding complexity
another example:
isAbsolute
itself can't be written using strongly typed paths; it has to be written asisAbsolute(string)
, losing the benefit of type safety + normalization we get bysimply typed paths
problem 2: very little benefit from distinguishing between those
eg:
likewise with
unixToNativePath
, and many other procs inospaths
eg:
joinPaths(path1, path2)
should work with:(AbsoluteDir | RelativeDir, AbsoluteFile | AbsoluteDir | RelativeFile | RelativeDir)
so we end up with either generics or with very redundant proc overloads; the only advantage of type safety we get here is preventing 1st arg
path1
to be a File; this doesn't seem like a good tradeoffproblem 3: not clear how to represent / provide API's for symlinks, filenames etc
is a filename (aka basename) just a string? or yet another distinct string? or a RelativeFile ? if it's just a string (the most likely option), we lose the benefits of type safety from hereafter for the resulting basename, eg:
[EDIT] problem 4: the type safety guarantees are not actual guarantees, and often violated in practice
the guarantees offered by pathutils.AbsoluteFile + friends are rather moot because code like AbsoluteFile(file) makes 0 checking (nor can it since it's an object constructor).
In practice these "guarantees" are often violated, eg see:
/
can return invalid AbsoluteFile Nim#13121AbsoluteFile"stdin"
in modules.nimAbsoluteFile"command line"
in modules.nimAbsoluteFile(x.strVal)
in pragmaLine which is a lie when user uses{.loc: "file.nim".}
, or uses--excessiveStackTrace:off
alternative A1 (simplest)
Path
could represent a normalized path, it'd be normalized during construction, eg:alternative A2 (typesafe and flexible)
use a class hierarchy
Note: I'm not distinguishing between absolute vs relative here; IMO it doesn't pull its weight.
API's shall use either Path, PathFile, or PathDir as appropriate in proc definitions.
We still get benefits of type safety at compile time where we need to distinguish, as well ability to use paths of unknown kind (a path, which can be a file or dir)
One thing to consider is whether this leads to runtime performance issues (due to dynamic dispatch) of practical impact. If it doesn't, this may be the best option.
The text was updated successfully, but these errors were encountered: