Init block for constructor body

In scala its very nice to be able to have code directly in the class body. Maybe this is a small thing, but it removes a bit of noise and nesting. What’s the design decision behind having the init block, does it help with compilation times or was it thought that it adds clarity?

Init blocks give a clean syntactic separation of declarations (from expressions). This gives us considerable freedom when it comes to choosing soft keywords as modifiers for class members, for example.

Historically, when we went for unprefixed annotations (that looked like modifiers), they couldn’t be mixed with expressions, so that was not an option (see http://blog.jetbrains.com/kotlin/2015/08/modifiers-vs-annotations/). After we dropped unprefixed annotations, we could have reconsidered init blocks, but didn’t.

Maybe we can work out some rules that would allow us to make init blocks optional now. Not sure. There have to be some restrictions in order to accomodate modifiers (that can be syntactically confused with infix expressions).

1 Like

Dedicated init block is clearest in my opinion.

“App” Scala class is not useful in Kotlin, for complex constructor you can use a factory function (a function with same class name).

2 Likes

@fvasco I’m not asking in relation to creating a “main” method using the App trait like in Scala. I’m asking because I’m converting over one of my libraries from Scala to Kotlin and putting this init {} everywhere is a bit annoying, but not the end of the world.

@abreslav It would be great to drop the init {} where its unambiguous, but I suppose its something that would be considered low priority.

Eg Scala code:

Personally, I find this Scala class with a mixture of method definitions, properties and initialization logic to be quite hard to follow, and I definitely think that it would benefit from extracting the initialization logic out of the flow of the class.

6 Likes

Actually that is a bad example as that class was large and doesn’t exist any more. I was in a rush at work and just picked the first one. There’s a better example at the end of this post.

If I have code like this in Scala

class Foo {
  private val boo = new Boo()
  boo.configure()
  logger.debug(s"Boo created = $boo")
}

In Kotlin I can do

class Foo {
  private val boo = createBoo()
  fun boo() : Boo {
    val boo = new Boo()
    boo.configure()
    logger.debug(s"Boo created = $boo")
    return boo
  }
}

Or

class Foo {
  private val boo = createBoo()
  init {
    boo.configure()
    logger.debug(s"Boo created = $boo")
  }
}

The init {} block to me is just noise. I appreciate that some people are going to say it adds clarity, and I suppose it stops people putting initialization code all over the class rather than just in one block, but imo it just adds noise and nothing else. Perhaps there’s a better way that I’m not yet familiar with?

It’s not a deal breaker either way. I’ve been using Scala for 5 years, and as I move my team into using more of Kotlin over Scala, there are a few things like this which surface which are just niggles. I hope the feedback is useful.

One other thing that you can do in Kotlin is:

class Foo {
    private val boo = createBoo().apply {
        configure()
        logger.debug(...)
    }
}
4 Likes

Ok that’s interesting.

From a KotlinTest user perspective, having to write:

class SomeTestClass: StringSpec() {
  init {
    …
  }
}

is annoying and cluttering compared to not having to have the init{…}.

Spek init block:

class SimpleTest : Spek({
... 
})

KotlinTest will support the style with the block in the super class constructor, too. But I consider it a hack.

In general I like the init block because it makes clear what is going on. In Scala I’ve seen more than once an irritating order of functions, variables and initialization logic. Not to be forced to use an init block may be nice in some cases (like in KotlinTest), but all in all I like the init block in Kotlin.

3 Likes

I also.
I don’t like sparse init logic, in my opinion this hack it fix the issue well.

I know you can abuse the constructor bodies in Scala, but that argument can be levied at any feature you don’t like. You don’t like operator overloading, you just say it ends up with horrible APIs. Haskellers will say if you allow inheritance it ends up with horrible APIs.

I think the init block is ugly and doesn’t add to readability. It’s hard to do things like create some vals and run some setup code (The apply method mentioned earlier in the thread is ok if you just need to act upon the vals as they are created).

However I accept I’m probably in the minority, most people don’t care, and that it’s unlikely to change.

No init block required? See example 3

http://latkin.org/blog/2017/05/02/when-the-scala-compiler-doesnt-help/

2 Likes

Since I clicked the link before reading “See example 3”, I’m citing it here :slight_smile:

Here’s a simple method definition on a class. Works fine.

class Widget {
    def doTheThing() = 
        synchronized {
            ...
        }
}

Somebody makes a small change - adds a log line at the start of the method.

class Widget {
    def doTheThing() = 
        info("Doin' that sweet thing")
        synchronized {
            ...
        }
}

Jolly good, doesn’t get much simpler than that. I think most code reviewers would glaze over it in the middle of a big PR. The compiler (the best code reviewer) is also 100% happy with this change and raises no objections.
Bug

Three of Scala’s features come into play:

  1. Method bodies without { } brackets can only consist of a single expression
  2. Any statements or expressions in a class definition, outside of member definitions, become part > of the primary constructor.
  3. Member definitions and primary constructor content can intermingle with no ordering restrictions.

So the resulting code really acts like this:

class Widget {
    // executes within Widget constructor
    synchronized {
        ...
    }

    def doTheThing() = {
        info("Doin' that sweet thing")
    }
}

What was previously the body of the doTheThing method has been silently bumped into the body of the primary constructor. Oops!
[…] Example 3 would have been prevented if methods were simply required to have { }, or if primary constructor content was required to come before method definitions.

I think that the init block just makes things more clear and source code easier to read (in general).

1 Like