1
votes
// Script A.scala
class A {
    private val privateVal = 1
}
object A extends App{ 
    println(new A().privateVal)
}

A.scala can be compiled and run with no problem since a companion object and its class can access each other’s private members.

$ scalac A.scala
$ scala A
1

Why would the same code show the companion object cannot access the private val in its companion class when interpreting?

$ scala A.scala
error: value privateVal in class A cannot be accessed in A
2
@SarveshKumarSingh This is just wrong. "Generally, a companion module of a class is an object which has the same name as the class and is defined in the same scope and compilation unit." This is all that's required, no problems extending anything. scala-lang.org/files/archive/spec/2.13/…Alexey Romanov
@SarveshKumarSingh I've never seen such a requirement. Do you have any reference where it talks about guarantees and limitations as you've mentioned?yǝsʞǝla
@AlexeyRomanov I have seen a lot of similar unpredictabilities (very common with pattern-matching) with "fancy" companion objects, which disappear as long as the companion object returns to being just an object. And yes, it is not mentioned anywhere that a companion object needs to be simple but neither will you find "fancy" companion objects anywhere in documentation.sarveshseri
@SarveshKumarSingh This really needs a definition of "fancy". Certainly I'd consider companion objects of collection types to be fancier than just extending App.Alexey Romanov
@AlexeyRomanov not really... DelayedInit is fancier. Anyways, OP's issue seems to have been resolved and was not really related to this.sarveshseri

2 Answers

6
votes

To get companion object in Scala a class and it's companion object have to be defined in the same file. It looks like that's what you are doing, especially when you are not using interpreter.

However, when you interpret code line by line in Scala, it wraps it in additional anonymous object to allow expressions to be defined without explicit classes or objects in REPL (more here).

Here is an illustration of the wrapping problem:

Doesn't work:

$ scala
Welcome to Scala version 2.10.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_222).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class A {
     |     private val privateVal = 1
     | }
defined class A

scala> object A extends App{ 
     |     println(new A().privateVal)
     | }
<console>:9: error: value privateVal in class A cannot be accessed in A
           println(new A().privateVal)
                           ^

Works if defined at the same time using :paste:

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

// Script A.scala
class A {
    private val privateVal = 1
}
object A extends App{ 
    println(new A().privateVal)
}

// Exiting paste mode, now interpreting.

defined class A
defined module A

BTW, I don't get this problem when running scala A.scala. Perhaps I'm using different version or settings.

If you can't use paste mode, or can't make interpreter read the whole file at once, a workaround is to wrap your code in any object to force interpretation of a single code block:

scala> object Workaround {
     | class A {
     |     private val privateVal = 1
     | }
     | object A extends App{ 
     |     println(new A().privateVal)
     | }
     | }
defined module Workaround
3
votes

:paste command can also be used to load the whole file, for example,

$ scala
scala> :paste A.scala

Also consider ammonite which seems to work out-of-the-box

amm A.scala