Heinrich Schmetterling
Heinrich Schmetterling

Reputation: 6884

scala: have constructor distinguish between apply and implicit parameter?

I have a class like this:

class A(arg: Int)(implicit i: Boolean) {
  def apply(v: Double): this.type = {
    // do stuff
    this
  }
}

and I want to create an instance of it by both initializing it and calling apply in the same line:

implicit val i = false
val a = A(arg=1)(v=2.0) // doesn't work
val a2 = (A(arg=1))(v=2.0) // doesn't work

Unfortunately the compiler assumes that v=2.0 is meant for the implicit parameter instead of being for the apply(). I tried a number of different syntaxes with inserting {}'s and ()'s, but none of them worked. I realize that v could be moved into the constructor, but in my case that isn't an option because A is subclassed and I don't want to add v to every subclass constructor. Is there a way to achieve this? Thanks.

Upvotes: 3

Views: 609

Answers (2)

Jean-Philippe Pellet
Jean-Philippe Pellet

Reputation: 59994

(I assume you have a constructor method in the companion object as you're not using new A.)

An option is to write it on two lines:

val atmp = A(1)
val a = atmp(2.0)

… but that's certainly not what you're after. Another equally dissatisfying option would be

val a = A(1)(implicitly)(2.0)

if you can live with that. Maybe the least ugly way to do it is to call apply explicitly:

val a = A(1).apply(2.0)

Lastly, you could add a new constructor method to the companion object that takes care of it all:

object A {
  def apply(arg: Int, v: Double)(implicit i: Boolean) = A(arg)(i)(v)
}

val a = A(1, 2.0)

Upvotes: 4

user166390
user166390

Reputation:

How about "ugly but it seems to work"...

class A(arg: Int)(implicit i: Boolean) {
  def apply(v: Double): this.type = this
}
implicit val i = false
// removing the :A makes this fail to run on simplyscala
val a1 = (new A(arg=1) : A)(v=2.0)
// also works with explicit method name
val a2 = new A(arg=1).apply(v=2.0)
// and works without implicit being ... implicitized
val a = new A(arg=1)(i)(v=2.0)

Honestly, no idea :-) However, consider this which might be some insight:

val a = (new A(arg=1))(2.0)
error: type mismatch;
 found   : Double(2.0)
 required: Boolean
       val a = (new A(arg=1))(2.0)

Whoa!

Happy coding.

Upvotes: 5

Related Questions