-
Notifications
You must be signed in to change notification settings - Fork 96
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
Add the package std module #2104
Conversation
Bencher Report
Click to view all benchmark results
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks reasonable so far.
With respect to semantic versioning, we could indeed parse it on the way (since we're running the regex anyway), I guess that will spare re-parsing it on the Rust side. It would also allow people (if we write the right contract) to use either a structured representation or a textual representation as an input. The final representation would be always structured (in fact even that is not required, we could keep a union, but I don't think it has much of an advantage).
Regarding optionals, I don't have a strong opinion myself but I guess we could look at the manifest format of some prominent languages that seem to have done things right and try to extract a common base of attributes that are required everywhere.
core/stdlib/std.ncl
Outdated
"%, | ||
|
||
keywords | ||
| Array String |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be enum tags instead? But it's less nice to express as a static type (we can use a contract like std.enum.EnumTag
or I don't remember how it's called, but for a static type we would need proper existential like exists a. [| ; a |]
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly I picked String
because the set of reasonable values is open and possibly large.
core/stdlib/std.ncl
Outdated
| { | ||
_ : [| | ||
'Path String, | ||
'Git { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to say that we should put each payload into its own type, but then that won't be usable in statically typed anymore as we don't have let type
s yet. Is that why you inlined all the structure here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, it was just because the first version had less fields, and then I didn't split it out as the number of fields grew. I'm not sure that static typing is a big concern here, as we don't have functions that consume and produce Manifest
s. (At least, not yet. But by the time we do, maybe we'll also have let type
...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, if we put it in the stdib, people might want to do that, so we could be tempted to leave it as it is and then later split it in a nicer way once we have let types, without disturbing user code.
On the other hand if we split it into contracts now this reduces what users can do with manifests but we can still introduce let-types later and that would be a backward-compatible improvement, which has been our strategy for many things up to now. So indeed if the stdlib doesn't really need the statically typed side, I guess we can go both ways.
🎉 All dependencies have been resolved ! |
Ok, I think this is ready for another look. I made the semver contracts parse their input to records. I think it's potentially useful to have the bare record contracts accessible (if nothing else, it provides a convenient way to document the structure of the records), so I adopted a pattern where I had a look at npm, cargo, and opam for inspiration on optionality of the fields, and there wasn't a lot of consensus. They all require a name, and both npm and opam require a version (although opam can try to infer the name and version from the directory structure). Opam requires a maintainer, but the others don't. Also, opam is the only one to require a tooling version ("opam-version"). I decided to go with mandatory name, version, authors, and minimal_nickel_version. I think the first two are uncontroversial. Authors is less necessary, but also very easy to fulfill (it accepts an empty array if you intentionally don't want to add it). Requiring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overall structure is fine. I'm a bit worried about the normalizing contracts, that can be very surprising if you don't expect it. There is a precedent in the stdlib already (TagOrString
), and it's useful, but I wonder if we should make it clearer in the documentation of each and every normalizing contract introduced here, with a caution at the beginning or something (for some it's not mentioned).
Yeah, I'm also not completely sure about the normalizing contracts. They came about because
These are basically in decreasing order of importance; I think the string-validating contracts are also an ok solution. Maybe we can just put a big "unstable" warning on the whole package module for now? |
Yeah, it's not the first time that this validation vs parsing comes into play, and there are good arguments for both. I tend to be ok with parsing, it makes it much easier to handle the resulting package in a standard way without having to worry about the 3 possible representations of each subfield. I just wonder how surprising it can be that a contract normalizes for a random user. I think I like the |
Depends on #2110
Adds a
package
module tostd
, with contracts related to package manifests.As I was making this PR, it occurred to me that maybe some of the contracts (e.g. the semver ones) could be parsing into a structured representation instead of just validating. What do you think?