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

ModuleSet: store a set rather than a map #292

Merged
merged 2 commits into from
Jun 21, 2024

Conversation

9999years
Copy link
Member

Previously, a ModuleSet wrapped a HashMap<NormalPath, TargetKind>. This had a number of undesirable consequences:

  • The data about a module's name (as its path) and how it was loaded (as its TargetKind) were split from each other and difficult to reference.
  • The module's import name wasn't explicitly stored anywhere, so we needed to convert between paths and dotted names when those were needed, which required hitting the disk.
  • There wasn't a type for the module's import name, so when we (e.g.) :unadded modules we needed to format them as strings.

Now, a ModuleSet wraps a HashSet<LoadedModule>.

  • A LoadedModule wraps a path but optionally contains the module's dotted name, if the module is loaded by name (and needs to be referred to by name to avoid the "module defined in multiple files" error).
  • The LoadedModule Display instance formats the module's import name correctly (with a dotted name if needed) and avoids hitting the disk or any string processing.
  • Labeled the PR with patch, minor, or major to request a version bump when it's merged.
  • Updated the user manual in docs/.
  • Added integration / regression tests in tests/.

@github-actions github-actions bot added the patch Bug fixes or non-functional changes label Jun 12, 2024
@9999years 9999years force-pushed the rebeccat/refactor-module-set branch 3 times, most recently from dc0a15c to a97ecd3 Compare June 13, 2024 18:00
@9999years 9999years force-pushed the rebeccat/refactor-module-set branch from a97ecd3 to a93cc3f Compare June 21, 2024 18:07
@9999years 9999years marked this pull request as ready for review June 21, 2024 18:09
Previously, a `ModuleSet` wrapped a `HashMap<NormalPath, TargetKind>`.
This had a number of undesirable consequences:
* The data about a module's name (as its path) and how it was loaded (as
  its `TargetKind`) were split from each other and difficult to
  reference.
* The module's import name wasn't explicitly stored anywhere, so we
  needed to convert between paths and dotted names when those were
  needed, which required hitting the disk.
* There wasn't a type for the module's import name, so when we (e.g.)
  `:unadd`ed modules we needed to format them as strings.

Now, a `ModuleSet` wraps a `HashSet<LoadedModule>`.

* A `LoadedModule` wraps a path but optionally contains the module's
  dotted name, if the module is loaded by name (and needs to be referred
  to by name to avoid the "module defined in multiple files" error).
* The `LoadedModule` `Display` instance formats the module's import name
  correctly (with a dotted name if needed) and avoids hitting the disk
  or any string processing.
@9999years 9999years force-pushed the rebeccat/refactor-module-set branch from a93cc3f to ffde017 Compare June 21, 2024 20:58
@9999years 9999years mentioned this pull request Jun 21, 2024
3 tasks
Comment on lines +31 to +42
/// Create a new module, loaded by path.
pub fn new(path: NormalPath) -> Self {
Self { path, name: None }
}

/// Create a new module, loaded by name.
pub fn with_name(path: NormalPath, name: String) -> Self {
Self {
path,
name: Some(name),
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think I might have asked this before, but what's the motivation for using these methods instead of using the LoadedModule constructor directly?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's the usual encapsulation reason. If you want to be able to write LoadedModule { path, name: None } then all of the struct's fields have to be public (and theoretically callers could use this to break invariants).

In reality, LoadedModule isn't exported publicly by the library and it would be basically fine to have the fields be public, but this is considered "good practice" so I lean towards it.

(Also constructor names can be a little more informative than setting struct fields directly.)

Comment on lines +45 to +46
pub fn path(&self) -> &NormalPath {
&self.path
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar question here: what's the advantage of doing loadedModule.path() instead of loadedModule.path?

Comment on lines +14 to +16
pub struct ModuleSet {
modules: HashSet<LoadedModule>,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Non-blocking, but I feel like this struct wrapper around the HashSet doesn't buy you much because most of the methods on ModuleSet are trivially wrapping methods on the underlying HashSet. You could probably pass around the HashSet directly instead of defining a separate ModuleSet struct.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, that's true. I like the type safety this gives, though, and I like being able to give semantically descriptive names to the methods. I think I'll keep this for now.

@9999years
Copy link
Member Author

I tried making the LoadedModule fields public and replacing ModuleSet with HashSet<LoadedModule>. The diff was +67 -148 (net -81 lines). I like the type safety and the implementation of ModuleSet has changed before, so I'm inclined to keep it at least for now.

@9999years 9999years merged commit 75e73e8 into main Jun 21, 2024
38 checks passed
@9999years 9999years deleted the rebeccat/refactor-module-set branch June 21, 2024 22:54
Copy link
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
patch Bug fixes or non-functional changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants