-
Notifications
You must be signed in to change notification settings - Fork 30
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
SIP-68: Reference-able Package Objects #100
base: main
Are you sure you want to change the base?
Conversation
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.
Overall I am in favor. It clearly improves on the status quo that we can refer to a package object in the natural way, without using the .package
encoding.
My only concern is that accepting this proposal would effectively bury the idea of dropping package objects. But on reflection I don't think we will be able to drop package objects anyway for the reasons that were stated here.
content/reference-package-objects.md
Outdated
|
||
## Limitations | ||
|
||
* `a.b` only expands to `a.b.package` when used "standalone", i.e. not when part of 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.
I don't think this limitation is necessary and it would be hard to implement. I think we can simply say that in selection path a.b.c
, a.b
means the full package, not just the package object. But it's OK to have operators. By the time we check valid package object use, we have already expanded out all these operators to selections.
Although package objects have been discussed [being dropped](https://docs.scala-lang.org/scala3/reference/dropped-features/package-objects.html) | ||
in Scala 3, no concrete plans have been made as to how to do so, and we argue that they | ||
are sufficiently useful that keeping them around is preferably to dropping them. |
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.
This means accepting this SIP is conditional on not dropping package object and therefore reworking how we teach top-level definitions, in particular https://docs.scala-lang.org/scala3/book/taste-toplevel-definitions.html# and https://docs.scala-lang.org/tour/package-objects.html need to be adapted. I guess we need to compare and contrast three kind of definitions:
- Regular class/object definitions in a package
- Top-level definition (including the special case of a companion object to an opaque type which is not treated like case 1)
- Package object
These three concepts behave differently with respect to:
- Regular scope
- Given scope
- Accessibility modifiers
For these three cases we need to consider:
- What happens in the scope where the definition is written
- What happens in a different scope in the same package
So there's a lot of hidden complexity here, which is currently under-documented, eventually deprecating package objects would have provided some relief here, but if we don't deprecate them I believe we'll need to do a much better job of explaining all these subtleties and providing guidelines on when to use what feature.
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 think we can avoid some of the complexity by changing the approach. The compiler treats package objects and toplevel definitions mostly the same. The only thing to explain is that toplevel definitions are partitioned: Classes and objects are treated as if they live directly in the package and all other definitions are treated as if they live in a synthesized package object. That needs to be explained anyway. (Maybe it is already explained? If not, a PR would be great.) After that, resolution proceeds the same for members of explicit and synthesized package objects.
I have no strong feeling on this proposal. It's a bit sad that we could not actually get rid of package objects, but oh well. One comment: the proposal argues that it improves regularity: I don't think this is a deal breaker, but it should be clearly acknowledged in the proposal, IMO. |
Another inconsistency that this proposal introduces: IIUC, the motivation for this proposal is to improve the ergonomics when package objects are deliberately used for building the API of a library. Like The Mill use case I don't understand so well as there's additional magic going on in the build tool. I looked a bit at
Again, the SIP seems fine and helpful if we keep package objects. (I wonder why in the examples they are declared as |
Fixes #4459 Fixes #3894 With this PR, all `.mill` files in a folder are in the same flat `package` namespace, similar to how normal Scala files work. The previous `import $file` syntax was inherited from Ammonite, and unfortunately never took off across the Scala community. In effect this makes `.mill` files behave almost exactly like `.scala` files, which is part of the longer term goal of removing special handling for `.mill` files. The code generation for the helper files is not changed at all in this PR, rather we just make use of Scala 3's `export` clauses to make them available under the main `build.mill`/`package.mill` file as well There is the caveat that the `package object`s in `.mill` files can be referenced via `build.foo.bar` without the trailing `.package`. Implementing this caveat is the cause of a lot of the hackiness in the codegen, which will hopefully go away once the upstream language feature lands scala/improvement-proposals#100 We leave the codegenned `import _root_.{build_ => $file}` in place so `import $file` will continue to work to ease in the migration, but are no longer the recommended way of referencing helper files
No description provided.