scala case class private apply method( repl bug ?) - scala

in Scala2.10.0 REPL
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_13).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class A private(i:Int)
defined class A
scala> A(1)
res0: A = A(1)
But if compile
$ scala -version
Scala code runner version 2.10.0 -- Copyright 2002-2012, LAMP/EPFL
$ cat Main.scala
package foo
case class A private (i:Int)
object Main extends App{
println(A(1))
}
$ scalac Main.scala
Main.scala:6: error: constructor A in class A cannot be accessed in object Main
println(A(1))
^
one error found
A.apply(1) is compile error.
is this Scala2.10.0 REPL bug?
FYI Scala2.9.2 REPL is following
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_13).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class A private(i:Int)
defined class A
scala> A(1)
<console>:10: error: constructor A in class A cannot be accessed in object $iw
A(1)
^

This definitely looks like a REPL bug.
Note that the constructor is correctly marked as private (in other words, new A(1) does not compile, as expected), it is only the factory (A.apply) that is wrongly public.

I see... You think you're calling the constructor when you write A(1). You're not. You're calling the factory added for you in the automatically generated (public) companion object and its public apply method.
Addendum
My day to be repeatedly wrong…
In the 2.10.0 REPL:
scala> object REPL { case class CC1 private(i: Int); val cc1_1 = CC1(23) }
<console>:7: error: constructor CC1 in class CC1 cannot be accessed in object REPL
object REPL { case class CC1 private(i: Int); val cc1_1 = CC1(23) }

The REPL has one huge semantic difference w.r.t. the ordinary compiler.
Consider what it means to be able to do this:
scala> val v1 = 23
v1: Int = 23
scala> val v1 = 42
v1: Int = 42
Could you do that in compiled Scala code? Of course not, it would be a prohibited double definition.
How does the REPL do this? In effect every line you enter is in a progressively more nested scope. The appearance of redefinition is actual shadowing. It's as if you did this:
object REPL1 {
val v1 = 23
object REPL2 {
val v1 = 42
object REPL3 {
// Next REPL line here...
}
}
}
So, how do you get companions? Put an explicit object (or other scope-forming construct) around them. And remember, no blank lines. The REPL will stop accepting input for a given "line" or "block" when you do.

Related

Scala: How to define the default value for a constructor parameter within the companion object?

The following Scala code does not compile in the Scala REPL 2.11.6:
object Foo {
val DefaultSize: Int = 10
}
class Foo(size: Int = Foo.DefaultSize)
The compile error is:
value DefaultSize is not a member of object Foo
class Foo(size: Int = Foo.DefaultSize)
Tested with Scala 2.11. This is particularly strange, since it follows exactly the accepted answer (in year 2012) here: Use method return value as default constructor parameter in Scala, which nowadays does not compile, neither. So how to achieve the intended behavior?
As explained in Programming in Scala, this is because the Scala REPL creates a new nested scope for each new statement you type in. This implies your code is interpreted as:
object Foo {
val DefaultSize: Int = 10
}
{
class Foo(size: Int = Foo.DefaultSize)
}
While the same book mentions that both the class and its companion object must be defined in the same source file, it seems that they furthermore must be in the same scope, since the code block above does not compile with scalac.
I know two ways to work around this in the REPL. As mentioned by others, you could enter :paste mode before defining the class and companion object. Alternatively, you could put both into the same scope, e.g., by defining them inside an object:
object My {
object Foo {
val DefaultSize: Int = 10
}
case class Foo(size: Int = Foo.DefaultSize)
}
Now you can use Foo as expected:
scala> new My.Foo()
res0: My.Foo = Foo(10)
scala> new My.Foo(20)
res1: My.Foo = Foo(20)
(I made class Foo a case class to get concise REPL results in the last code block. The answer works without this change, however.)

Cannot get scala file to run

I have 2 questions:
1) I'm trying to get the List menu in this program to appear either by calling scalac then scala or print it using the REPL but I'm a little confused because this uses packages. I tried to run this using
scalac Fruits.scala
scala bobsdelight\Fruits
but I get java.lang.NoClassDefFoundError: bobsdelights\Fruits wrong name: bobsdelights/Fruits)
If someone can please show me how to execute this script that would be great
2)I'm also trying to create a new Apple object by calling new Fruits.Apple in the REPL by loading the file first but I get:
error: type Apple is not a member of object Fruits
new Fruits.Apple``
This example is in the Programming In Scala book.
package bobsdelights
abstract class Fruit(
val name: String,
val color: String
)
object Fruits {
object Apple extends Fruit("apple", "red")
object Orange extends Fruit("orange", "orange")
object Pear extends Fruit("pear", "yellowish")
val menu = List(Apple, Orange, Pear)
}
REPL example:
$ scala
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> :pa bobsdelight.scala
Pasting file bobsdelight.scala...
scala> Fruits.menu
<console>:12: error: not found: value Fruits
Fruits.menu
^
scala> import bobsdelight._
<console>:11: error: not found: value bobsdelight
import bobsdelight._
^
scala> import bobsdelights._
import bobsdelights._
scala> Fruits.menu
res1: List[bobsdelights.Fruit] = List(bobsdelights.Fruits$Apple$#6c17c0f8, bobsdelights.Fruits$Orange$#260e3837, bobsdelights.Fruits$Pear$#88b76f2)
If you try to "run" a class with no main method:
$ scala bobsdelights.Fruits
java.lang.NoSuchMethodException: bobsdelights.Fruits.main([Ljava.lang.String;)
Idiom for runnable app:
object Fruits extends App {
object Apple extends Fruit("apple", "red")
object Orange extends Fruit("orange", "orange")
object Pear extends Fruit("pear", "yellowish")
val menu = List(Apple, Orange, Pear)
println(menu)
}
and
$ scalac bobsdelight.scala && scala bobsdelights.Fruits
List(bobsdelights.Fruits$Apple$#4f8e5cde, bobsdelights.Fruits$Orange$#504bae78, bobsdelights.Fruits$Pear$#3b764bce)

Bypassing deprecation warnings in Scala 2.11

There is a nice way to avoid deprecation warnings in Scala 2.10 (and before) by invoking the deprecated method from a deprecated local def. Unfortunately, it doesn't work in Scala 2.11. Is there an alternative?
From this Scala issue comment, we can define methods calling deprecated API in a deprecated class/trait, and have the companion object to this class extend it without a warning:
scala> #deprecated("", "") def foo = 0
foo: Int
scala> object Test { #deprecated("", "") class Coral { def fooForwarder = foo }; object Coral extends Coral }
defined object Test
scala> Test.Coral.fooForwarder
res1: Int = 0

Case class for value object visibility?

Is it worth, to control the visibility of case class that represent value object ? If so, is a visibility modifier on the case class enough, or using an explicit companion object, and a private constructor, would be better ?
Version 1:
case class MyClass private/protected/private[] {}
Version 2:
case class MyClass private
object MyClass {
def apply = {
new MyClass
}
}
In sum, the question could be summarize as how to deal with value object in scala.
I personally want to enforce the no new, so that is i want to change something in the creation of the object, I can do it at any time. That is, by simply adding a companion object when necessary.
A visibility modifier on the case class constructor does not propagate to the companion object, so creating one yourself by hand with the exact same apply method is unnecessary.
You can verify this yourself trivially:
$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class X private () {}
defined class X
scala> new X
<console>:10: error: constructor X in class X cannot be accessed in object $iw
new X
^
scala> X()
res1: X = X()
Note that just plain X is the name of the companion object. You can't get a new X by naming the companion object; that won't call its apply method even if a no-argument apply exists. So you can't omit the empty parameter list ().
The above is all true in the REPL, but compiled code fails.

scala: tracing implicits selection and other code magics

When trying to figure how a library works, implicit conversions are confusing. For example, looking at an expression like 'val foo: Foo = 1', what converts 1 to Foo?
Is it possible to instruct the scala library (or REPL) to print out the code paths that are executing while evaluating an expression?
You can add "-Xprint:typer" to the compiler command line (or "-Ybrowse:typer" for a swing GUI browser) to see the code with the conversions explicitly applied.
As an alternative to printing out the conversions, one must realize implicits can't just come out of the blue. You have to bring them into scope in some way. The alternatives are:
Explicit import statement. Watch out for import x.y._ when y is an object, as this is the only way to bring in an implicit into scope.
The object companion of the class that is being converted into something else.
The object companion of the target class, as long as that target is made explicit somehow (such as in your example).
Note that the object scala.Predef is all imported into scope by default, which is how Scala's default implicits get into scope.
scalac -print prints the code after implicit type conversions where applied.
class A{
val x : String = "hi" drop 1
}
Will result in:
package <empty> {
class A extends java.lang.Object with ScalaObject {
#remote def $tag(): Int = scala.ScalaObject$class.$tag(A.this);
private[this] val x: java.lang.String = _;
<stable> <accessor> def x(): java.lang.String = A.this.x;
def this(): A = {
A.super.this();
A.this.x = scala.this.Predef.forceRandomAccessCharSeq(
scala.this.Predef.stringWrapper("hi").drop(1));
()
}
}
}