> On Wed, Aug 29, 2012 at 1:03 AM, Sébastien Bocq <sebastien.b...@gmail.com>wrote:
>> Shouldn't the code below compile since declarations in package `baz`
>> cannot be accessed from `bar` or from `foo`?
> The spec 4.7 says a member is importable if it isn't object-private,
> private[this].
> I guess the next question is, if I have a bunch of stuff in a module that
> I don't want to share, and I also don't want to write private[pkg]
> everywhere, should I just use an object instead of a package?
To ffwd to the relevant test: this issues two ambiguity errors with
current trunk, but only one with that branch.
object Bippy {
private class Node
}
class Bippy {
import Bippy._
import scala.xml._
def f(x: Node): String = ??? // ambiguous, because Bippy.Node is accessible
}
class Other {
import Bippy._
import scala.xml._
def f(x: Node): String = ??? // unambiguous, because Bippy.Node is
inaccessible
}
...
t3160ambiguous.scala:8: error: reference to Node is ambiguous;
it is imported twice in the same scope by
import scala.xml._
and import Bippy._
def f(x: Node): String = ??? // ambiguous, because Bippy.Node is accessible
^
one error found
Thanks for reminding me of the recent thread, where Jason had pointed out
the spec.
That
https://groups.google.com/d/topic/scala-debate/Tt1XnL_JF7k/discussion was another great thread. Or good thread anyway. It would have been a
rhetorically great thread if Jason had had the opportunity to respond to
Daniel's "(hence the "regardless")" with a "(hence the "irregardless")".
I'm not 100% persuaded by the argument to disambiguate. More examples
besides Node ("What *is* this node anyway?") might be compelling.
The counter-argument is: We rely on the compiler for various kinds of
support, especially where the brain fails, such as variance annotations.
Here the compiler is telling us: "You asked for ambiguous imports, are you
sure you didn't really mean the one that isn't accessible?" Do we mean to
reply, "I always know what I'm importing, even wildcardly."
An alternative solution is: "Yes, I really meant to get public API from bar
and protected API from baz, please ignore private bar.Foo." Let me fix
that:
import public bar._
import protected baz._
This way, I'm not depending upon accidents of access (such as whether this
code has been refactored to another package).
As a lark,
import public bar.Foo
would verify that Foo is public and not private [foob].
Is it true that most Scala code is public by dint of limiting keystrokes;
and anything that's not public is made so by the inliner? But seriously,
this use case should interoperate with any future package object module
feature; maybe I could say
import package bar._
to mean whatever API is "exported" in package object bar (not including
implicits that are protected[bar], for instance).
Sorry for scala-debating on scala-language, I got carried away.
On Wed, Aug 29, 2012 at 10:28 AM, Paul Phillips <pa...@improving.org> wrote:
> To ffwd to the relevant test: this issues two ambiguity errors with
> current trunk, but only one with that branch.
> object Bippy {
> private class Node
> }
> class Bippy {
> import Bippy._
> import scala.xml._
> def f(x: Node): String = ??? // ambiguous, because Bippy.Node is
> accessible
> }
> class Other {
> import Bippy._
> import scala.xml._
> def f(x: Node): String = ??? // unambiguous, because Bippy.Node is
> inaccessible
> }
> ...
> t3160ambiguous.scala:8: error: reference to Node is ambiguous;
> it is imported twice in the same scope by
> import scala.xml._
> and import Bippy._
> def f(x: Node): String = ??? // ambiguous, because Bippy.Node is
> accessible
> ^
> one error found
On Wed, Aug 29, 2012 at 4:03 PM, Som Snytt <som.sn...@gmail.com> wrote:
> I'm not 100% persuaded by the argument to disambiguate. More examples
> besides Node ("What *is* this node anyway?") might be compelling.
> The counter-argument is: We rely on the compiler for various kinds of
> support, especially where the brain fails, such as variance annotations.
> Here the compiler is telling us: "You asked for ambiguous imports, are you
> sure you didn't really mean the one that isn't accessible?" Do we mean to
> reply, "I always know what I'm importing, even wildcardly."
It isn't the impact on the importer which is a problem. Should I be
able to have private things without ruining the namespaces of everyone
who imports from its owner? That's what's at issue here.
package object foo {
private type PrivateToFoo = String
}
In truth I don't care what the person who imported foo._ meant,
whether he meant to import my private types or not. I do care about
whether I can have type PrivateToFoo at all -- which I can't as long
as it's going to create spurious ambiguities.
This is the one that really is private, right?, because a package object is
really an object, and private to an object means private[this],
object-private. (Conjecture.)
> In truth I don't care what the person who imported foo._ meant,
> whether he meant to import my private types or not. I do care about
> whether I can have type PrivateToFoo at all -- which I can't as long
> as it's going to create spurious ambiguities.
Well, I guess we care if the importer runs into us at Starbucks and starts
yelling at us because we added a private class Node. And maybe he's
carrying a concealed weapon.
Otherwise we don't really care. In terms of a contract, private or
protected API is as much APIsh as public API. There are many potential
clients, including the new person on the team adding a method to a
companion object with privates exposed. Object-private also matters for
variance, so it's clearly a privileged access boundary. (PiS 19.7, "You
might wonder whether this code passes the type checker." I'm still
wondering, but I swear that before the day I die, I will know, albeit
without ceasing to wonder.)
Maybe import should default to "import public" (though I'm slightly
inclined toward the status quo)? Import non-private seems slightly
arbitrary. It makes me feel that Scala access modifiers and
packaging/modularity is deeply different from Java's, and my old
expectations about private must change.
package object bar {
type PrivateToBaz = Int
}
package object baz {
private type PrivateToBaz = String
}
package baz {
private case class Biff(b: String)
}
package objprv {
import bar._
import baz._
object Test {
//val a = Biff()
val y: PrivateToBaz = 1 // OK?
def main(args: Array[String]) {
}
}
On Wed, Aug 29, 2012 at 5:59 PM, Som Snytt <som.sn...@gmail.com> wrote:
> On Wed, Aug 29, 2012 at 4:57 PM, Paul Phillips <pa...@improving.org> wrote:
>> package object foo {
>> private type PrivateToFoo = String
>> }
> This is the one that really is private, right?, because a package object is
> really an object, and private to an object means private[this],
> object-private. (Conjecture.)
I too enjoy attempting to retrofit rationale to observed behavior, but
this is another helping of bug, one way or another. This is
ambiguous:
object foo { private type Node = Int }
object fooz { type Node = String }
class A {
import fooz._
import foo._
def f(x: Node) = ???
}
./c.scala:10: error: reference to Node is ambiguous;
it is imported twice in the same scope by
import foo._
and import fooz._
def f(x: Node) = ???
^
one error found
... yet if either foo or fooz is a package object instead of a regular
object, it compiles.
It all makes sense to me, so, quick, before I forget --
On Wed, Aug 29, 2012 at 6:30 PM, Paul Phillips <pa...@improving.org> wrote:
> On Wed, Aug 29, 2012 at 5:59 PM, Som Snytt <som.sn...@gmail.com> wrote:
> > On Wed, Aug 29, 2012 at 4:57 PM, Paul Phillips <pa...@improving.org>
> wrote:
> >> package object foo {
> >> private type PrivateToFoo = String
> >> }
> > This is the one that really is private, right?, because a package object
> is
> > really an object, and private to an object means private[this],
> > object-private. (Conjecture.)
Sorry, I wasn't actually thinking and I was rushing out to pick up the
Kindergartner. Or is that Kindergärtner?
The (only) difference is that package objects have no notion of companion
class. They don't, do they? I hope not, because it crashes M7 with an
error that breathes frustration:
how can getCommonSuperclass() do its job if different class symbols get the
same bytecode-level internal name: top/baz/Biff$
So it makes sense for private to be taken as private[this] in a package
object, though it makes import seem irregular for that case. (I haven't
look at the source yet on that.)
> I too enjoy attempting to retrofit rationale to observed behavior, but
> this is another helping of bug, one way or another.
Wash the bug down with some beer and it's an evening.
> object foo { private type Node = Int }
> object fooz { type Node = String }
> class A {
> import fooz._
> import foo._
> def f(x: Node) = ???
> }
> ./c.scala:10: error: reference to Node is ambiguous;
> it is imported twice in the same scope by
> import foo._
> and import fooz._
> def f(x: Node) = ???
> ^
> one error found
> ... yet if either foo or fooz is a package object instead of a regular
> object, it compiles.
For me, with package object fooz it's still ambiguous.
Also regular is when extending, import baz._ picks up BazzieImportable, not
BazzieOnly.
class Bazzie {
protected[this] type BazzieOnly = String
//protected type BazzieImportable = String
I'll submit a PR to the Scala puzzlers repo. As usual, it's not puzzling
but exceedingly regular. I'll report if I can't explain something the
morning after.
On Wed, Aug 29, 2012 at 9:29 PM, Som Snytt <som.sn...@gmail.com> wrote:
> The (only) difference is that package objects have no notion of companion
> class. They don't, do they?
I don't know; it's a place where I've tried without success to obtain
clarification. One can try to derive the answer empirically, and one will
wind up with all the answers:
package foo
// this compiles: package object bippy accesses bippy's private x
package object bippy { private val y = 5 ; def f(x: bippy) = println(x.x) }
// this fails: class bippy can't see package object's private y
class bippy { private val x = 1 ; def f = println(bippy.y) }
// ./a.scala:5: error: object y is not a member of package foo.bippy
// class bippy { private val x = 1 ; def f = println(bippy.y) }
// ^
// one error found