Class initialization style guidance


#1

As I understand Scala classes do not have a special name for constructor and the class initialization is just written in the body of the class.
It looks counter-intuitive that it is possible to write some initialization code before one method and some after that.

Are there any suggestions how to better organize the class initialization code? May be write it before fields and methods declaration or just do all in setup/init method and call this method during initialization?


#2

No need for an init/setup method unless you have init/setup code that you
want to be invoked at a time other than object creation time.

I’d group things by function.


#3

I don’t like the look of a method like

class Foo {
  ...
  def init(): Unit = { ... }

  init()
  ...
}

either, but it has one advantage: it lets you keep any vals created for
initialization purposes scoped inside init(), and not exposed as
public class members. This can happen even if you introduce a scope
with braces, like:

class Foo {
  ...
  { //init code
    val bar = new Bar
    val baz = new Baz(42, bar)
    initSomeLibraryWereUsing(bar,baz)
  }
  ...
}

Here you’ll end up with bar and baz as public members of Foo.
That may or may not be what you want; in most cases, I’d bet it’s not.


#4

When I’ve encountered this situation, I’ve tended to keep my class’s
constructor limited to assigning fields, and move any initialization
logic beyond that to a factory method on the companion object. That’s
not possible in every case, but it lets you sidestep the issue of
interleaving init code in class bodies.


#5

Welcome to Scala 2.12.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_141).
Type in expressions for evaluation. Or try :help.

scala> class Foo {
| {
| val bar = “Hello”
| val baz = “World”
| println(bar + baz)
| }
| }
defined class Foo

scala> val foo = new Foo
HelloWorld
foo: Foo = Foo@663f237a

scala> foo.bar
:13: error: value bar is not a member of Foo
foo.bar
^

scala> foo.baz
:13: error: value baz is not a member of Foo
foo.baz
^


#6

That’s great news, since that’s the behavior I’d always hoped for!

I stand corrected, this was a false alarm. I couldn’t reproduce the
unwanted-members issue in a 2.10, 2.11, or 2.12 REPL, but I could in an
old version of my IDE. It looks like what I saw previously was an IDE
(or maybe presentation compiler) bug.

So I’ll amend my advice to the OP: consider a factory method on the
companion object, or a nested scope in the class body.


#7

Do you mean defining the apply method on the companion object and then creating the object instance without the “new” keyword?
Something like this:

[code]class Hello(var name: String) {
var greeting: String = ""
def hello() = greeting
}

object Hello {

def apply(name: String): Hello = {
val hello = new Hello(name)
hello.greeting = s"Hello $name";
hello
}

def main(args: Array[String]): Unit = {
val hello = Hello(“James”)
println(hello.hello())
}
}
[/code]


#8

@curoli: Try it without that inner set of brackets in the class, should work as expected.


#9

Yeah, that’s a good way. You could also name the factory method
anything you want (though apply is very often convenient and idiomatic):

val foo: Foo = Foo.fromBar(bar)

or whatever.

Note that in your example, you could get the same behavior without the
factory method:

class Hello(var name: String) {
  var greeting: String = "Hello $name"
  def hello() = greeting
}

but that’s probably due to the simplified nature of the example;
initialization logic is a real issue.


#10

[quote=“Clint_Gilbert, post:9, topic:1623”]
Yeah, that’s a good way. You could also name the factory method anything you want (though apply is very often convenient and idiomatic) [/quote]

Is it possible in this case to prohibit the object substantiation using the ‘new’ operator, something like private constructor in Java?

Yes. It just not to do the sample over-complicated.


#11

Yes, you can make constructors private - secondary constructors just like
any other method, and the primary constructor can be made private by
putting “private” in front of the body like this:

class A private { … }

Best, Oliver


#13

Oliver Ruebenacker wrote:

[curoli] curoli http://users.scala-lang.org/u/curoli
August 29

Yes, you can make constructors private - secondary constructors just like
any other method, and the primary constructor can be made private by
putting “private” in front of the body like this:

class A private { … }

Actually, it doesn’t go “in front of the body” but after the class name (and
any TypeParamClause after the class name). Consider this case:

class A private (someParam: SomeType) { … }

Daniel