Rory Rory - 1 month ago 12
Scala Question

Pattern matching on a Try lazy val in Scala?

Is it possible to pattern match on a

lazy val
, declared as a
Try
, like this?

lazy val kafkaProducer: Try[producer.KafkaProducer[Array[Byte], String]] = Try(kafkaProducerSettings.createKafkaProducer())
...
kafkaProducer.get match {
case Success(_) => Source.single(producerRecord()).runWith(Producer.plainSink(kafkaProducerSettings, kafkaProducer.get))
case Failure(x) => Future.failed(x)
}


I'm getting this error:

constructor cannot be instantiated to expected type;
[error] found : akka.actor.Status.Success
[error] required: org.apache.kafka.clients.producer.KafkaProducer[Array[Byte],String]
[error] case Success(_) => Source.single(producerRecord()).runWith(Producer.plainSink(kafkaProducerSettings, kafkaProducer.get))


Note, this alternative code works, but I'm not sure it's the "Scala way":

lazy val kafkaProducer: producer.KafkaProducer[Array[Byte], String] = kafkaProducerSettings.createKafkaProducer()
...
val tryAccessLazyKafkaProducer = Try(kafkaProducer)
if (tryAccessLazyKafkaProducer.isSuccess) {
Source.single(producerRecord()).runWith(Producer.plainSink(kafkaProducerSettings, kafkaProducer))
} else {
Future.failed(tryAccessLazyKafkaProducer.failed.get)
}

Answer Source

It's definitely possible, you just have the wrong Success type imported:

found   : akka.actor.Status.Success

You need scala.util.Success instead

One thing you mustn't do is call Try.get, which will explode if the returned type is a Failure. Instead, do:

import scala.util.Success
import scala.util.Failure

kafkaProducer match {
    case Success(producer) => Source.single(producerRecord()).runWith(Producer.plainSink(kafkaProducerSettings, producer))
    case failure: Failure => failure
}

lazy is just a language construct which makes sure the value is only ever evaluated once. The underlying type, whether lazy or not, is still a Try which you can do what you do with it.