Considering this simple example:
trait A { def a: String = "a"; def a2: String }
case class C(b: String, c: String) extends A {
val a2 = "a2"
}
val c = C("b", "")
val copy = c.copy(c="c")
When I update field c with .copy(c="c"), are other fields(a,a2 and b) copied? Event though only their references are copied, if I have a huge hierarchy tree, will .copy become very costly?
Similarly:
class Foo {
val list = List(1,2,3,4,5,6)
}
val foo1 = new Foo
val foo2 = new Foo
Do foo1 and foo2 share an instance of List, or every time I instantiate a Foo it creates a new List? What if list is a var instead of val?
Generally Scala is immutable, you usually have to handle mutable cases yourself. Also case classes are immutable by nature and their copy method is generated by the compiler. So yes, they would share the same object reference. This is one of the reasons immutability is nice.
Your second question is a bit different. In that case the classes are constructed one after the other in seperate contexts.
It's also a good idea to check what's being compiled:
>scalac -print test.scala
[[syntax trees at end of cleanup]] // test.scala
package test {
class Foo extends Object {
private[this] val list: List = _;
<stable> <accessor> def list(): List = Foo.this.list;
def <init>(): b.Foo = {
Foo.super.<init>();
Foo.this.list = immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1, 2, 3, 4, 5, 6}));
()
}
}
}
From this we can see Scala creating a new list each time. Changing this to var won't change anything, we can check:
>scalac -print test.scala
[[syntax trees at end of cleanup]] // test.scala
package test {
class Foo extends Object {
private[this] var list: List = _;
<accessor> def list(): List = Foo.this.list;
<accessor> def list_=(x$1: List): Unit = Foo.this.list = x$1;
def <init>(): b.Foo = {
Foo.super.<init>();
Foo.this.list = immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1, 2, 3, 4, 5, 6}));
()
}
}
}
It only generated a setter method for it (def list_=(x$1: List)).
If you would like to reference the same list in both cases then initialize it with an object's default list:
object Foo {
val DefaultList = List(1,2,3,4,5,6)
}
class Foo {
var list = Foo.DefaultList
}
Which compiles to the following:
>scalac -print test.scala
[[syntax trees at end of cleanup]] // test.scala
package test {
object Foo extends Object {
private[this] val DefaultList: List = _;
<stable> <accessor> def DefaultList(): List = Foo.this.DefaultList;
def <init>(): test.Foo.type = {
Foo.super.<init>();
Foo.this.DefaultList = immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1, 2, 3, 4, 5, 6}));
()
}
};
class Foo extends Object {
private[this] var list: List = _;
<accessor> def list(): List = Foo.this.list;
<accessor> def list_=(x$1: List): Unit = Foo.this.list = x$1;
def <init>(): test.Foo = {
Foo.super.<init>();
Foo.this.list = Foo.DefaultList();
()
}
}
}
As you can see the list is only created once and then the reference through the def DefaultList(): List assigned on each Foo class instantiation.
To answer my own first question:
The concrete vals in a trait are implemented as a Java static method:
// scala
trait A { def a: String = "a"; }
// java
public static java.lang.String a(A);
Code:
0: ldc #8 // String a
2: areturn
Of course, a static method can't be copied. So I don't need to worry about huge hierarchy tree.
The abstract val is implemented as a hard-coded constant:
// scala
trait B { def b: String }
case class C() { def b = "b" }
// java
public java.lang.String b();
Code:
0: ldc #47 // String b
2: areturn
It's fine as well.
The only thing(s) will be copied when I call .copy() are the fields in constructor parameter list.
Related
I have following code snippet:
class Data(i: Int)
class Person(#transient val data: Data) extends java.io.Serializable
class Student(data: Data) extends Person(data)
I thought data is a field of Student class, but actually, it is a method of Student,
classOf[Student].getMethods.foreach(m => println(m.getName()),
The above code prints data
I would ask why data becomes method of Student, but not field,
thanks!
In Scala classes all public fields are actually private fields accessed via public methods.
This can be demonstrated using just your Data class, examining its status after phase 4 ("typer") of compilation.
%%> cat so.sc
class Data(i: Int)
%%> scalac -Xprint:4 so.sc
[[syntax trees at end of typer]] // so.sc
package <empty> {
class Data extends scala.AnyRef {
<paramaccessor> private[this] val i: Int = _;
def <init>(i: Int): Data = {
Data.super.<init>();
()
}
}
}
As you can see, val i is private[this] and if you run classOf[Data].getFields.isEmpty it will return true.
Now let's add a public field or two to it.
%%> cat so.sc
class Data(val i: Int) {
val x = 'X'
}
%%> scalac -Xprint:4 so.sc
[[syntax trees at end of typer]] // so.sc
package <empty> {
class Data extends scala.AnyRef {
<paramaccessor> private[this] val i: Int = _;
<stable> <accessor> <paramaccessor> def i: Int = Data.this.i;
def <init>(i: Int): Data = {
Data.super.<init>();
()
};
private[this] val x: Char = 'X';
<stable> <accessor> def x: Char = Data.this.x
}
}
We see that both vals, i and x, are private[this], and classOf[Data].getFields.isEmpty will still return true, but now there are also methods, def i and def x, that are public and return the expected values of Data.this.i and Data.this.x respectively.
Person has public getter method called data.
scala> :javap -public Person
Compiled from "<console>"
public class $line3.$read$$iw$$iw$Person implements java.io.Serializable {
public $line3.$read$$iw$$iw$Data data();
public $line3.$read$$iw$$iw$Person($line3.$read$$iw$$iw$Data);
}
Because Student is a child of Person it inherits this method.
Student has data too, but without var or val it's just a local variable, which is visible only in the body of Student, so it's not a member.
You can read more at Tour of Scala: Classes
Expectedly, the following initialisation order without lazy val throws null pointer exception
class Foo {
Bar.x // NullPointerException
}
object Bar extends Foo {
val x = 42
}
object Hello extends App {
Bar
}
Examining -Xprint:jvm output, and referencing #paradigmatic answer, we see this is due to Foo's constructor running first and calling Bar.x() before Bar.this.x is initialised in Bar's constructor:
class Foo extends Object {
def <init>(): example.Foo = {
Foo.super.<init>();
Bar.x();
()
}
};
object Bar extends example.Foo {
private[this] val x: Int = _;
<stable> <accessor> def x(): Int = Bar.this.x;
def <init>(): example.Bar.type = {
Bar.super.<init>();
Bar.this.x = 42;
()
}
};
However, why is null pointer also thrown when x is lazy like so
object Bar extends Foo {
lazy val x = 42
}
Analysing -Xprint:jvm output in lazy case we have
class Foo extends Object {
def <init>(): example.Foo = {
Foo.super.<init>();
Bar.x();
()
}
};
object Bar extends example.Foo {
final <synthetic> lazy private[this] var x: Int = _;
#volatile private[this] var bitmap$0: Boolean = _;
private def x$lzycompute(): Int = {
Bar.this.synchronized(if (Bar.this.bitmap$0.unary_!())
{
Bar.this.x = (42: Int);
Bar.this.bitmap$0 = true
});
Bar.this.x
};
<stable> <accessor> lazy def x(): Int = if (Bar.this.bitmap$0.unary_!())
Bar.this.x$lzycompute()
else
Bar.this.x;
def <init>(): example.Bar.type = {
Bar.super.<init>();
()
}
};
where it seems to me it should work due to the bitmap$0 guard
<stable> <accessor> lazy def x(): Int = if (Bar.this.bitmap$0.unary_!())
Bar.this.x$lzycompute()
else
Bar.this.x;
Runtime field accessors check -Xcheckinit seems to be satisfied on my machine with Scala 2.12.8, so why NullPointerException when lazy val x?
I don't think this NPE is related to val at all. Check this:
class Foo {
Bar.anyMethod
}
object Bar extends Foo {
def anyMethod = ???
}
object Hello extends App {
Bar
}
//java.lang.NullPointerException
Foo is trying to run constructor on Bar while Bar is still under construction. So that's what your Foo is doing too before calling x.
Btw if you put everything into Hello with main method you will get StackOverflow instead of NPE in both mine and your cases.
object Hello {
def main(args: Array[String]): Unit = {
class Foo {
Bar.anyMethod
}
object Bar extends Foo { //<- Bar is like local val now instead of field
def anyMethod= ??? // of package object, so stack is available now.
}
Bar
}
}
the bellow code :
scala> class A {
| def hi = "Hello from A"
| override def toString = getClass.getName
| }
defined class A
scala> val a = new A()
a: A = A
scala> a.toString
res10: String = A
scala> println(s"${a.toString}")
$line31.$read$$iw$$iw$A
It is printing ok when using a.toString expression, not when using println(s"${a.toString}"). The problem is getClass.getName. In other cases it works nice.
Thanks in advance for any help
REPL filters its output to hide template wrappings.
$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.
scala> class A
defined class A
scala> val a = new A
a: A = A#4926097b
scala> a.getClass
res0: Class[_ <: A] = class A
scala> $intp.isettings.
allSettings deprecation deprecation_= maxAutoprintCompletion maxPrintString toString unwrapStrings
scala> $intp.isettings.unwrapStrings = false
$intp.isettings.unwrapStrings: Boolean = false
scala> a.getClass
res1: Class[_ <: A] = class $line3.$read$$iw$$iw$A
You can also compare output clipping:
scala> (1 to 1000).mkString
res2: String = 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629...
scala> println((1 to 1000).mkString)
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
Scroll right to see the ellipsis on the first line.
Since names of classes inside REPL are different, REPL needs to convert internal names back. It does it well enough when displaying strings, but fails when string is passed to an external method, e.g. println or toList:
scala> a.toString
res1: String = A
scala> a.toString.toList
res2: List[Char] = List($, l, i, n, e, 4, ., $, r, e, a, d, $, $, i, w, $, $, i, w, $, A)
scala> "$line4.$read$$iw$$iw$A"
res3: String = A
Run the scala repl using: scala -Xprint:parser
Then run the successive commands. The output $line3.$read$$iw$$iw$A represents the path to the A object. $line is a package, $read and $iw are objects under which the object A is nested.
For the case of println(s"${a.toString}")
scala> println(s"${a.toString}")
[[syntax trees at end of parser]] // <console>
package $line5 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line3.$read.$iw.$iw.A;
import $line4.$read.$iw.$iw.a;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res0 = println(StringContext("", "").s(a.toString))
}
}
}
}
[[syntax trees at end of parser]] // <console>
package $line5 {
object $eval extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
lazy val $result = $line5.$read.$iw.$iw.res0;
lazy val $print: String = {
$line5.$read.$iw.$iw;
"" <-- // SOMETHING OFF HERE! NO OUTPUT STRING BEING GENERATED?
}
}
}
$line3.$read$$iw$$iw$A
Now for the case of a.toString:
scala> a.toString
[[syntax trees at end of parser]] // <console>
package $line6 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line3.$read.$iw.$iw.A;
import $line4.$read.$iw.$iw.a;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res1 = a.toString
}
}
}
}
[[syntax trees at end of parser]] // <console>
package $line6 {
object $eval extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
lazy val $result = $line6.$read.$iw.$iw.res1;
lazy val $print: String = {
$line6.$read.$iw.$iw; // *CORRECTLY GENERATES THE RESULT STRING.*
"".$plus("res1: String = ").$plus(scala.runtime.ScalaRunTime.replStringOf($line6.$read.$iw.$iw.res1, 1000))
}
}
}
res1: String = A
It is the way REPL is compiling A. In a simple app like below there are no issues
Each line in the REPL is wrapped into it's own package.. and that auto generated package name is what you see prepended to class name A.
object ScalaApp extends App {
class A {
def hi = "Hello from A"
override def toString = getClass.getName
}
val a = new A()
println(a.toString)
println(s"${a.toString}")
}
Assuming no multiple inheritance and no concerns about interoperability with Java, are the two following declarations equal?
sealed trait Foo { def x: Int }
case object Bar extends Foo { val x = 5 }
and
sealed abstract class Foo(val x: Int)
case object Bar extends Foo(5)
First, some modifications to your code (see below). I dropped the case as it is not relevant here. I also added val in the constructor of Foo2 as x is otherwise not accessible in Bar2.
sealed trait Foo { def x: Int }
object Bar extends Foo { val x = 5 }
sealed abstract class Foo2(val x: Int)
object Bar2 extends Foo2(5)
object Main {
def main(args: Array[String]) : Unit = {
println( Bar.x )
println( Bar2.x )
}
}
Are the two following declarations equal?
We need to define, what equal means:
Equal wrt. general structure: No. A trait is not an abstract class. A trait can have no constructor parameters, while a class can. On the other hand, a class or object (here Bar2) can only derive from one (abstract) class, while it could mix-in multiple traits. A good comprehesion on traits vs. abstract class is given here: http://www.artima.com/pins1ed/traits.html#12.7 if you need to decide on a trait or a class.
Equal wrt. byte code: No. Just run javap -v <classfile> to convince yourself
Equal wrt. Bar and Bar2 only: Yes. Both can be accessed and used identically. Both are singletons and they expose a member variable x that is readable (but not writable) from outside.
Also the output of scalac -print is quite helpful, to see what is going on:
sealed abstract trait Foo extends Object {
def x(): Int
};
object Bar extends Object with com.Foo {
private[this] val x: Int = _;
<stable> <accessor> def x(): Int = Bar.this.x;
def <init>(): com.Bar.type = {
Bar.super.<init>();
Bar.this.x = 5;
()
}
};
sealed abstract class Foo2 extends Object {
<paramaccessor> private[this] val x: Int = _;
<stable> <accessor> <paramaccessor> def x(): Int = Foo2.this.x;
def <init>(x: Int): com.Foo2 = {
Foo2.this.x = x;
Foo2.super.<init>();
()
}
};
object Bar2 extends com.Foo2 {
def <init>(): com.Bar2.type = {
Bar2.super.<init>(5);
()
}
};
object Main extends Object {
def main(args: Array[String]): Unit = {
scala.this.Predef.println(scala.Int.box(Bar.x()));
scala.this.Predef.println(scala.Int.box(Bar2.x()))
};
def <init>(): com.Main.type = {
Main.super.<init>();
()
}
}
No, these are not equivalent and can lead to trouble later with initialization order. I've added exactly the same line of code to each, showing they were never equal code blocks.
sealed trait Foo {
def x: Int
val calc = x * 5 / 2 //at the time this runs, x is actually 0
}
case object Bar extends Foo {
val x = 5
}
sealed abstract class Foo2(x: Int){
val calc = x * 5 / 2
}
case object Bar2 extends Foo2(5)
println(Bar.calc)
println(Bar2.calc)
//output 0 12
I've seen the args.foreach(arg => println(arg)), but when I search the doc http://www.scala-lang.org/api/current/index.html#scala.Array . I don't find it there and its companion object doc.
Any advice?
Thanks
Array gets operations such as foreach from scala.collection.mutable.ArrayOps - so you can lookup ArrayOps in the documentation to see what methods are available on arrays.
Predef contains a number of implicit conversion methods to make these available for arrays.
Unfortunately you can't see in the Scala API documentation for Array that these methods are available via the implicits in Predef.
As Jesper said, it's not really easy to find documentation on methods acquired via implicit conversions.
The ones defined for Array and the rationale behind them are explained here.
One (not particularly handy...) general way of finding out where a particular method comes from (in cases like yours, where it comes from an implicit conversion) is to use the -print option of the scala REPL.
If you run scala -print you will get:
scala> Array(1,2,3,4)
// ..... omitted for brevity
res0: Array[Int] = Array(1, 2, 3, 4)
scala> res0 foreach (println)
[[syntax trees at end of cleanup]]// Scala source: <console>
package $line2 {
final object $read extends java.lang.Object with ScalaObject {
def this(): object $line2.$read = {
$read.super.this();
()
}
};
#SerialVersionUID(0) final <synthetic> class $read$$iw$$iw$$anonfun$1 extends
scala.runtime.AbstractFunction1 with Serializable {
final def apply(x: java.lang.Object): Unit = scala.this.Predef.println(x);
final <bridge> def apply(v1: java.lang.Object): java.lang.Object = {
$read$$iw$$iw$$anonfun$1.this.apply(v1);
scala.runtime.BoxedUnit.UNIT
};
def this(): anonymous class $read$$iw$$iw$$anonfun$1 = {
$read$$iw$$iw$$anonfun$1.super.this();
()
}
};
final object $read$$iw$$iw extends java.lang.Object with ScalaObject {
private[this] val res1: scala.runtime.BoxedUnit = _;
<stable> <accessor> def res1(): Unit = ();
def this(): object $line2.$read$$iw$$iw = {
$read$$iw$$iw.super.this();
$read$$iw$$iw.this.res1 = {
scala.this.Predef.intArrayOps($line1.$read$$iw$$iw.res0()).foreach({
{
(new anonymous class $read$$iw$$iw$$anonfun$1(): Function1)
}
});
scala.runtime.BoxedUnit.UNIT
};
()
}
};
final object $read$$iw extends java.lang.Object with ScalaObject {
def this(): object $line2.$read$$iw = {
$read$$iw.super.this();
()
}
}
}
[[syntax trees at end of cleanup]]// Scala source: <console>
package $line2 {
final object $eval extends java.lang.Object with ScalaObject {
#volatile protected var bitmap$0: Int = 0;
<stable> <accessor> lazy def $result(): Unit = {
if ($eval.this.bitmap$0.&(1).==(0))
{
$eval.this.synchronized({
if ($eval.this.bitmap$0.&(1).==(0))
{
{
$eval.this.$print();
$line2.$read$$iw$$iw.res1()
};
$eval.this.bitmap$0 = $eval.this.bitmap$0.|(1);
()
};
scala.runtime.BoxedUnit.UNIT
});
()
};
()
};
private[this] val $print: java.lang.String = _;
<stable> <accessor> def $print(): java.lang.String = $eval.this.$print;
def this(): object $line2.$eval = {
$eval.super.this();
$eval.this.$print = {
$line2.$read$$iw$$iw;
""
};
()
}
}
}
1
2
3
4
If you look for .foreach inside this code, you will find the relevant line, that tells you the method is actually called on intArrayOps:
scala.this.Predef.intArrayOps($line1.$read$$iw$$iw.res0()).foreach(