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

_root_ should always refer to the root package #6217

Closed
scabug opened this issue Aug 11, 2012 · 19 comments
Closed

_root_ should always refer to the root package #6217

scabug opened this issue Aug 11, 2012 · 19 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Aug 11, 2012

I see no reason this should be allowed to happen, and a lot of reasons it shouldn't.

package foo
package _root_

object Test {
  import _root_.scala.Option
}
./a.scala:5: error: object scala is not a member of package foo._root_
  import _root_.scala.Option
                ^
one error found

So to be clear, that source should not compile, but it should not compile because root should be a reserved word. The whole point of root is to know what you are importing. Tying this into another ticket I opened recently:

// a.scala
package foo

import _root_.scala.Option

% scalac3 ./a.scala 
% mkdir -p foo/_root_
% scalac3 ./a.scala 
./a.scala:3: error: object scala is not a member of package foo._root_
import _root_.scala.Option
              ^
one error found
@scabug
Copy link
Author

scabug commented Aug 11, 2012

Imported From: https://issues.scala-lang.org/browse/SI-6217?orig=1
Reporter: @paulp

@scabug
Copy link
Author

scabug commented Aug 11, 2012

@paulp said:
Jira is turning underscore-root-underscore into italics, which I'm sure is obvious, but anyway.

_root_

@scabug
Copy link
Author

scabug commented Jul 10, 2013

@adriaanm said:
Unassigning and rescheduling to M6 as previous deadline was missed.

@scabug
Copy link
Author

scabug commented Feb 19, 2014

@paulp said:
Maybe I misunderstand why this was given the label "error-messages" but this isn't about error messages. Perhaps an example is needed where it DOES compile but should certainly NOT compile.

package p {
  package _root_ {
    package scala {
      sealed trait Option[+T] { def isEmpty = false ; def donkey = 5 }
      final case class None[T]() extends Option[T] { def get: T = null.asInstanceOf[T] }
      final case class Some[T](x: T) extends Option[T] { }
    }
  }
}
// Meanwhile, in some other file
package p {
  object Test {
    import _root_.scala.Option
    def f[T](x: Option[T]) = x.donkey
  }
}

There is no "donkey" method on root .scala.Option. If root is to behave like any other relative package, then there is quite literally no reason for it to exist.

And conversely, this does NOT compile, but certainly SHOULD. root.scala.Option does have a "get" method.

package p {
  object Test2 {
    import _root_.scala.Option
    def f[T](x: Option[T]) = x.get
    // ./a.scala:18: error: value get is not a member of p._root_.scala.Option[T]
    //     def f[T](x: Option[T]) = x.get
    //                                ^
    // one error found
  }
}

@scabug
Copy link
Author

scabug commented Feb 19, 2014

@adriaanm said (edited on Feb 19, 2014 6:54:52 AM UTC):
I co-opted the label to group my fixes that introduce new errors (as opposed to those that change the behavior of normal/successful compilation). Sorry about the confusion

@scabug
Copy link
Author

scabug commented Feb 20, 2014

@adriaanm said (edited on Feb 20, 2014 5:33:06 AM UTC):
deprecated in: scala/scala#3565

@scabug
Copy link
Author

scabug commented Feb 20, 2014

@adriaanm said:
This patch does not go far enough, I know. Not sure if we should push this all the way to all identifier names.
As a follow-up, I'm considering hard-wiring root in an import to the root package, and disallowing it as a nested name.

@scabug
Copy link
Author

scabug commented Mar 20, 2017

@paulp said:
Noting for the record that the patch didn't wind up going even as far as not far enough: it didn't survive the review process. So as of scala 2.12.1 you can still name a package _root_ and it will subvert any _root_ referencing imports, with no warnings (even under -Xfuture.)

@scabug
Copy link
Author

scabug commented Mar 20, 2017

@dwijnand said:
I was thinking about this issue today too for some reason.

I wonder what you think: one could argue that you must know what you're doing if you're defining you're own \_root\_, and perhaps it being definable is a handy last resort?

@scabug
Copy link
Author

scabug commented Mar 20, 2017

@paulp said:
"You" can't rely on knowing what "you" are doing because there's no reason to expect the value of these two "you"s to coincide.

If packages had been defined up front to be relative to an abstract root, and there were some facility for controlling where that root is, that could be useful - albeit impractical on the jvm, which doesn't offer any way to virtualize packages short of bytecode rewriting. But the whole reason people use _root_ is they want to know what they're getting. It's explicitly NOT a virtual path.

It's in the specifiction: "The special predefined name _root_ refers to the outermost root package which contains all top-level packages."

@SethTisue
Copy link
Member

@jvican has taken an interest in this recently

@jvican
Copy link
Member

jvican commented Mar 5, 2018

Yes. Making _root_ a keyword is the way to fix this issue IMO, since the word is already a standard. I'll put up a SIP about it.

@som-snytt
Copy link

The PR just enforces that import _root_.blah.blah means the root package always, and warns if there is a badly named symbol in scope.

Hopefully this averts enshrining _root_ as a keyword. Because then it would sit in the front of the spec and we'd have to look at it all the time. As it is, the homely identifier can sit in the back with other miscellany, not quite as forgotten as the chapter on XML syntax, but willing on occasion to step out and perform a humble duty when needed, before returning to that quiet if lonely place under the jeers of onlookers.

@mkeskells
Copy link

Is there any reason that a package should ever be named _root_?
It seems to me that special semantics at the start of the import statement is the wrong way to go, and to do so should be illegal
i.e.
import _root_.foo is always foo in the root package
import a._root_.foo should not compile
package _root_ should not compile

@mkeskells
Copy link

mkeskells commented Nov 27, 2018

personally I would prefer the denotation of the root package not to be a legal character sequence for a package, and more obvious to the eye, e.g.

import /foo means from the root
import foo means not from root

but that is probably not achievable any more

@jvican
Copy link
Member

jvican commented Nov 27, 2018

@som-snytt
Copy link

This PR would be the minimally useful warning only, in lieu of possible future syntaxes. Disallowing _root_ in some contexts is a good job for a linter.

@mkeskells your example is already illegal:

scala 2.13.0-M5> :pa
// Entering paste mode (ctrl-D to finish)

package p { object X }
package q { package p { class C { import _root_.p ; def f = p.X } } }

// Exiting paste mode, now interpreting.


                 package q { package p { class C { import _root_.p ; def f = p.X } } }
                                                          ^
<pastie>:2: error: _root_ cannot be imported
There were compilation errors!

I haven't excavated the why, although import _root_._ comes to mind. Note that this example wouldn't work anyway, as the import cannot shadow the enclosing p. It could shadow other imports, though.

@mkeskells
Copy link

@jvican I didn't know about that - looks good
@som-snytt - to clarify - (I hadn't realised that there was additional special casing on the special casing!)
import _root_.foo.bar is always bar in the foo package
import a._root_.foo should not compile
package _root_ should not compile

I wonder what havoc val _root_ : Int = 0 would have
or def _root_ : String
or type aliases and generic parameters

Instead lets make the root, in whatever form not a legal identifier!

@som-snytt
Copy link

som-snytt commented Dec 11, 2018

To summarize the compromise, _root_ is a soft keyword as lead element of a qualifier; a warning is emitted if it "shadows" an ordinary _root_ in scope. That covers the use case and the gotcha. Any further tightening of screws could be taken to the SIP committee.

@SethTisue SethTisue removed this from the Backlog milestone Jan 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants