Search code examples
scalafriend

Friend access in Scala


Consider

  • a function f defined in package p1

  • a package p2 which does not contain p1

  • a package p3 which does not contain p2 or p1 nor it is contained by p2 or p1.

In Scala, is it possible to declare that f is accessible from package p2 but not from other packages (such as p3)?


Solution

  • If I stretch your rules to their limits, it is possible. Though I'm not sure if that's intended or that you forgot a rule.

    scala> :paste -raw
    // Entering paste mode (ctrl-D to finish)
    
    package p1 {
      object O { private[p1] def f = println("f") }
    
      package p2 {
        object O { def x = p1.O.f }
      }
    }
    
    // Exiting paste mode, now interpreting.
    
    
    scala> :paste -raw
    // Entering paste mode (ctrl-D to finish)
    
    package p3 {
      object O { def x = p1.O.f }
    }
    
    // Exiting paste mode, now interpreting.
    
    <pastie>:2: error: method f in object O cannot be accessed in object p1.O
      object O { def x = p1.O.f }
                              ^
    There were compilation errors!
    

    If p2 also can't be contained by p1, I don't think there's a way to guarantee that f can't be accessed from somewhere else. You can do some tricks with sealed traits and implicits.

    package p2 {
      object O { def x = p1.O.f }
    }
    
    package object p2 {
      sealed trait Friend
      private[p2] implicit val p2Friend: Friend = new Friend {}
    }
    
    package p1 {
      object O { def f(implicit friend: p2.Friend) = println("f") }
    }
    
    package p3 {
      object O { def x = p1.O.f(null) }
    }
    

    But now as you can see you can still cheat in package p3. And without cheating f can't be accessed in p1 itself, because p1 also doesn't have the necessary implicit.

    You can check in f whether or not friend is null. Then p3 can't really use f but it will only fail at runtime, not at compile time. Although if someone is passing around null they can't really complain if things blow up at runtime.