Scala initialization behaviour - scala

Please look at the following code.
trait MyTrait { val myVal : String }
class MyClass extends MyTrait { val myVal = "Value" }
class MyClass2(val myVal: String) extends MyTrait
Why does the initialization order differ in case of MyClass and MyClass2?
The constructor of MyClass will be as
MyClass() {
MyTrait$class.$init$(this);
myVal = value
}
The constructor of MyClass2 will be
MyClass2(String myVal) { this.myVal = myVal; MyTrait$class.$init$(this) }
I think the initialization order should be as MyClass2's constructor does, the same for both cases.

At the end of section 5.1 of the Scala specification, the following is defined:
Template Evaluation. Consider a template sc with mt 1 with mt
n {stats}. If this is the template of
a trait (§5.3.3) then its
mixin-evaluation consists of an eval-
uation of the statement sequence
stats. If this is not a template of a
trait, then its evaluation consists of
the following steps.
First, the superclass constructor sc is evaluated (§5.1.1).
Then, all base classes in the template’s linearization (§5.1.2) up
to the template’s superclass denoted
by sc are mixin-evaluated.
Mixin-evaluation hap- pens in reverse
order of occurrence in the
linearization.
Finally the statement sequence stats is evaluated.
Note, however, that the constructor parameters may be used by any constructors that follow it. Therefore, it needs to be initialized before them. This is made explicit at the end of section 5.1.1:
An evaluation of a constructor
invocation x.c targs. .
.(argsn) consists of the following
steps:
First, the prefix x is evaluated.
Then, the arguments args1 , . . . , argsn are evaluated from left to
right.
Finally, the class being constructed is initialized by evaluating the
template of the class referred to by
c.
This you don't have any problem with, but you do have a problem with {stats} being executed last. The reason why {stats} is executed last is that it may reference attributes of its ancestor classes and traits, whereas the ancestors obviously have no knowledge about its descendants. Therefore, the ancestors need to be fully initialized before {stats} gets executed.
Of course, it is possible that you do need early initialization. This is covered by section 5.1.6: Early Definitions. Here's how you'd write it:
class MyClass extends { val myVal = "Value" } with MyTrait

Related

Scala syntax question in Rocket-chip config.scala

I just learned about the scalar to study rocket chips.
I see some strange codes in the Config.scala of Rocket-chip
abstract class Field[T] private (val default: Option[T])
{
def this() // 1st-this
= this(None) // 2nd-this
def this(default: T) // 3rd-this
= this(Some(default)) // 4th-this
}
The above code has 4 of this. I think 2nd/4th-this are identical.
But I'm not sure 2nd/4th-this are represent Field class self-type or not.
If they are self-type, 1st/3rd-this are to be what??
I'm frustrated since I can't tell the definition of the above four this.
Could you explain this?
These are called auxiliary constructors (see https://docs.scala-lang.org/scala3/book/domain-modeling-tools.html#classes).
The "main constructor" is the one defined by the class declaration:
class Field[T] private (val default: Option[T])
With this you can create instances of Field only by passing a Option[T]. Like Field(None) or Field(Some(...)).
Then, you have 2 additional auxiliary constructors. They are defined as regular methods but they need to be called this.
The following adds a constructor that accepts no parameter so that you can create instances with Field() and it will be the same as Field(None). The 2nd this refers to the main constructor.
def this() = this(None)
Same principle for the other auxiliary constructors which allows to call Field(x) instead of Field(Some(x)).
Note that you could achieve the same with apply methods in a companion object.

Singleton Object vs Companion Object in Class

I have written the following code:
class a {
object c {
var a = "STATIC"
def m() = print("STATIC METHOD")
var f = () => print("STATIC FUNCTION")
}
}
object m {
def main(args: Array[String]) = {
var o = new a()
o.c.m()
}
}
Can I say that the variables, functions and methods that are declared in object c can be static?
If I change name of object c with a then will the object becomes a companion object?
Scala has no true meaning of 'static' that Java does.
The fact that objects have a backing on the JVM that uses static methods / fields is a leaking implementation detail that you only need to deal with if using Java/JVM interop.
Unless you explicitly need that interop, you need to stop thinking of declared objects as 'static' and instead think of them as singletons within their given scope.
An inner object nested under a class, means that there is only ever going to be 1 instance of that object, for each class instance, unlike inner classes which could have multiple instances.
This applies at the top level as well, except that Scala can do additional compatibility with other JVM languages, and mark some of the methods/members as static.
Fields and methods in an object are how Scala declares things that you would have used static for in Java. I guess you can, for intuition sake, say that those fields are usually static (as in only one of those in a JVM at once).
However, in your example, you put an object inside a class, making it no longer static. You can easily check this with a few lines of code (that you can find here on Scastie).
class MyClass {
object Embedded {
val a = "field"
def m = println("method")
}
}
val a = new MyClass().Embedded
val b = new MyClass().Embedded
// prints "a and b are different objects"
if (a eq b)
println("a and b are the same object")
else
println("a and b are different objects")
Regarding your second question: no, class and object must be in the same scope in order for it to be a companion object. You can find more details on the Scala Language Specification.
I quote from there:
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. Conversely, the class is called the companion class of the module.
To answer you questions:
The methods and fields in a.c are not globally static because they need an instance of a to exist. If a were an object, a.c would be static too.
If you want to have a companion object with static fields and methods for your class a it has to be defined outside of a's code block, like this:
class a {
/* non-static stuff goes here */
}
object a {
/* static stuff goes there */
def m() = print("STATIC METHOD")
}
You must keep both in the same file, defining the object or the
class first doesn't matter, so it generally depend on a convention or what makes most sense depending on use case.
If you want to call the static method a.m inside the class a, you will still need to call it a.m and not just m. But the class a will be able to use private fields and methods of object a, because they are companions.
As others already said, static doesn't really exist in Scala, but the concept transpires from Java since Scala is in most cases compiled into java bytecode.
Last advice, the convention is usually the same in Scala and in Java for classes and object: the first-letter of their name should be uppercase (except in some advanced Scala cases)

In Scala, How to perform compile-time type check on companion object?

An easy thing to do in many languages but not in Scala is:
Define archetype 'Super', such that all implementations of 'Super' has to define a constructor 'create()'.
I found this constraint very important and is able to identify a lot of problems before runtime. However this feature is only partially enforced in Java (by defining an 'abstract' static method that always throws an error) and completely missing in Scala (companion object is completely detached from class and cannot be enforced in archetype).
is there a macro or tool that allows me to do this?
UPDATE Sorry my question was missing context and examples. Here is a formal use case in scala:
In project A, we define an interface that can be extended by all subprojects:
trait AbstractFoo {}
This interface should always have a default 0-parameter builder/constructor, so project A can initialize it on-demand, however, the implementation of each constructor is unknown to project A:
object AbstractFoo {
def default[T <: AbstractFoo: ClassTag](): T
}
So the problem becomes: How to rigorously define AbstractFoo, such that for all subprojects of A, any implementation(s) of AbstractFoo:
case class Foo(...) extends AbstractFoo
must satisfy:
'Foo' must have a 0-parameter builder/constructor defined (presumably in its companion object)
calling AbstractFoo.defaultFoo can invoke this 0-parameter builder/constructor
It should be noted that in an alternative conditions, a solution exists which is to define every companion object as an implicit type class:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
}
object AbstractFoo {
implicit object Foo extends FooBuilder[Foo] {
def default() = {...}
}
def default[T <: AbstractFoo: FooBuilder](): T = {
implicitly[FooBuilder[T]].default
}
}
Such that if the implicit object is undefined the compiler will give an implicit not found error (my code snippet may have some syntax error, the idea is from http://www.cakesolutions.net/teamblogs/demystifying-implicits-and-typeclasses-in-scala)
Unfortunately it's not always convenient, because this subproject of A is usually unknown to project A. Yet the default implicit builder cannot be redefined, this makes every invocation of default() more covoluted.
I believe scala is a very extendable language, so there should be at least 1 way to enforce it whether if using macro, annotation or other metaprogramming techniques. Is my question clear enough now?
UPDATE2: I believe I found the solution after carefully study Scaladoc, there is a comment hidden in a corner:
if there are several eligible arguments which match the implicit parameter’s type, a most specific one will be chosen using the rules of static overloading resolution (see Scala Specification §6.26.4):
...
Implicit scope of type arguments (2.8.0)
...
So all I need is to write an implicit function in FooBuilder:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
implicit def self = this
}
object Foo extends FooBuilder[Foo]
So everytime someone call:
default[Foo]
scala will refer to the scope of class Foo, which include object Foo, which contains the implicit value Foo, and eventually find the 0-parameter constructor.
I think this definition is better than defining it under object FooBuilder, since you can only define FooBuilder once, thus its not quite extendable. Would you agree with me? If so, could you please revise your answer so I can award you point?
I don't understand why an abstract class or even a Trait won't allow this to be done?
abstract class DefineCreate{
def create(): Unit
}
case class Foo(one: Int)
object Foo extends DefineCreate{
def create(): Unit = { Console.out.println("side-effect") }
}
Thus I force a user to make a create method on the object in question because all implementations of DefineCreate must do so in order to compile.
Update Following Comments
Well, without having to resort to macros and the like, you could achieve the same sort of thing with type classes:
trait Constructor[A]{
def create(): A
}
object Construct{
def create[A](implicit cr: Constructor[A]): A = cr.create()
}
Which doesn't explicitly force the companion object to sprout methods but it does force a user to make the type class if they want to use the Constructor.create[Foo] pattern.

Why does auxiliary constructor not see import done in the class?

The code below gives a compile error:
class Info(val x: String)
object Info {
val default = new Info("top")
}
case class Data(x: String) {
import Info.default
def this() = this(default.x)
}
Error:(11, 23) not found: value default
def this() = this(default.x)
Why is symbol default not seen in the constructor, in spite of the import?
Further experiments show it is not only import. Replacing import line with a def (or even val) does not help, still the error persists:
def default = Info.default
Scoping doesn't work the way you expected because of the scoping of self constructor invocations (when secondary constructors invoke the primary constructor):
The signature and the self constructor invocation of a constructor
definition are type-checked and evaluated in the scope which is in
effect at the point of the enclosing class definition, augmented by
any type parameters of the enclosing class and by any early
definitions of the enclosing template.
In other words, the scope in effect for the expression default.x is the scope outside Data.
This is confusing because textually it looks like that expression is inside the class.
This rule has to do with lexical scope and not with evaluation order.
You have to move the import outside the class definition.
For fun, scoping is slightly broken in the following case:
object Playroom {
def default = "playing"
case class Toy(squeezeMsg: String = default)
object Toy {
def default = "srsly"
}
}
object Test extends App {
import Playroom._
println(Toy())
println(new Toy())
}
which is this puzzler. Generally speaking, it's more idiomatic (and robust) to use apply methods on the companion.
This is behaving according to specs. The body of the class is part of the so called primary constructor. The auxiliary constructor(s) needs to start by calling the primary or another auxiliary defined before. Assuming you only have one auxiliary, since the call to primary must be the first statement in your auxiliary, it means that during this first statement you do not have access to anything defined inside the primary. After the first call is done, then you can access any of the members and imports defined in the primary.
In your example, the problem is that the import (import Info.default) is not visible to the first statement of your auxiliary. If you replace it with def this() = this(Info.default.x) it should work.
Example:
The following compiles fine since the call to Constant is done after the call to the primary.
class G(i: Int) {
val Constant = 1
// No argument auxiliary constructor
def this() = {
this(3) // Call to primary
println(Constant * 2)
}
}
The following does not compile since the call to Constant is done before the call to the primary, which means that Constant has not been created yet.
class G(i: Int) {
val Constant = 1
// No argument auxiliary constructor
def this() = {
this(Constant) // This will cause an error!
}
}
Solution:
Have any constants you need defined in the companion object. The companion object is by definition initialized first, so you will be able to access any members of it from within the constructors of your class.
object G {
val Constant = 1
}
class G(i: Int) {
// No argument auxiliary constructor
def this() = {
this(G.Constant) // This now works!
}
}
In scala, any fields defined in the class is not available until after the primary constructor is invoked. To fix it is usually used companion object with apply method.

Calling a constructor through java reflection in scala 2.10

Before Scala 2.10 I had
class A {
class B(b: Int) {
}
}
and somewhere in code recreate class B with
val bCtor = bInstance.getClass.getConstructor(classOf[Int])
bCtor.newInstance ...
and everything was fine. It was with signature public A$B(Int)
Now constructor have 2!!! arguments. It has a new signature public A$B(A,Int). What is argument with type A? I don't have access to A class from my function. It there any workaround?
For example newInstance with arguments - It doesn't work anymore for inner class
Be carful not to confuse java inner class with scala path-dependent type
(from the Programming In ScalaBook) :
A path-dependent type resembles the syntax for an inner class type in Java, but there is a crucial difference: a path-dependent type names an outer object, whereas an inner class type names an outer class
So in your case bInstance is related to an aInstance.
My assumption is that aInstance is the object passed as the first parameter to this constructor.
You can use an unconstrained self-type annotation to have a way to refer to the A's version of this even from within B (where this now refers to the B instance).
package rrs.scribble
object OuterInner {
class Outer { oThis =>
class Inner {
def identify { printf("I am %s; I'm inside of %s%n", this, oThis) }
}
val inner = new Inner
}
def oiTest {
val o1 = new Outer
o1.inner.identify
}
}
In the REPL:
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
scala> import rrs.scribble.OuterInner._
import rrs.scribble.OuterInner._
scala> oiTest
I am rrs.scribble.OuterInner$Outer$Inner#63d0d313; I'm inside of rrs.scribble.OuterInner$Outer#22d1b797
First, adding A as the first constructor argument is also the way it works in Java:
If this Class object represents an inner class declared in a non-static context, the formal parameter types include the explicit enclosing instance as the first parameter.
Second,
What is argument with type A? I don't have access to A class from my function.
If you have a B (as seems from your example), then you can access its enclosing instance (it doesn't seem to be documented officially, and so may change in the future versions of Java):
val aInstance = bInstance.getClass.getDeclaredField("this$0").get(bInstance)
bCtor.newInstance(aInstance, ...)
If you don't, then you can't create a B (without an A), but you shouldn't be able to. What would you expect this code to return?
class A(foo: Int) {
class B {
def bar = foo
}
}
classOf[A#B].getConstructor().newInstance().bar
#evantill is right, the only constructor of B is A$B.<init>(A, Int). So bInstance.getClass.getConstructor(classOf[A], classOf[Int]) works.