4

What is the Scala equivalent of this Java code, where someMethodThatMightThrowException is defined elsewhere?

class MyClass {
    String a;
    String b;

    MyClass() {
        try {
            this.a = someMethodThatMightThrowException();
            this.b = someMethodThatMightThrowException();
        } finally {
            System.out.println("Done");
        }
    }
}
Paul Draper
  • 78,542
  • 46
  • 206
  • 285

4 Answers4

5
class MyClass {
  private val (a, b) =
    try {
      (someMethodThatMightThrowException(),
       someMethodThatMightThrowException())
    } finally {
      println("Done")
    }
}

try is an expression in Scala, so you can use it's value. With tuples and pattern matching you can use statement to get more than one value.

Alternatively you could use almost the same code as in Java:

class MyClass {
  private var a: String = _
  private var b: String = _

  try {
    a = someMethodThatMightThrowException()
    b = someMethodThatMightThrowException()
  } finally {
    println("Done")
  }
}
senia
  • 37,745
  • 4
  • 88
  • 129
  • Snazzy. Kind of wish you'd delete the java alternative, though. Unless you're willing to add semicolons and `null` to the initializers to make it look more authentically noobish. Edit: where did `private` come from? – som-snytt Sep 03 '13 at 20:35
  • @som-snytt: After deleting java alternative I should replace solution with `sealed case class` with `private` constructor and move not-safe call to factory `apply` method. `private` comes from my laziness, it should be [`private[PackageName]`](http://stackoverflow.com/a/714814/406435). – senia Sep 03 '13 at 23:41
1

with companion object

case class MyClass(a: String, b: String)

object MyClass {
   def apply() = try { 
      new MyClass(
         a = someMethodThatMightThrowException(), 
         b = someMethodThatMightThrowException()
      ) 
   } finally {
      println("Done") 
   }
}

with constructor overload a little bit harder, because we can't wrap this(...):

def tryIt[T](something: => T) = try{
      something
   } finally {
      println("Done") 
   }

case class MyClass(a: String, b: String) {
   def this() = this(
      tryIt(someMethodThatMightThrowException),  
      tryIt(someMethodThatMightThrowException)
   ) 
}
Bask.ws
  • 823
  • 4
  • 6
1

What is a or b assigned if an exception occurs? Wrap a and b in a Try to handle the exceptional cases. You can also pattern match on these to extract values.

scala> class MyClass(val a: Try[String], val b: Try[String])
defined class MyClass

scala> new MyClass(Try("foo"(0).toString), Try("foo"(3).toString))
res0: MyClass = MyClass@6bcc9c57

scala> res0.a
res1: scala.util.Try[String] = Success(f)

scala> res0.b
res2: scala.util.Try[String] = Failure(java.lang.StringIndexOutOfBoundsException: String index out of range: 3)

scala> res0.a.get
res3: String = f

scala> res0.b.get
java.lang.StringIndexOutOfBoundsException: String index out of range: 3
        at java.lang.String.charAt(String.java:658)
        ...

Edits for comment. Uses default argumens for a and b.

null is bad but that's what you asked for. See Option

class MyClass(val a: Try[String] = null, val b: Try[String] = null)

scala> new MyClass(Success("a"))
res50: MyClass = MyClass@625aaaca

scala> res50.a
res51: scala.util.Try[String] = Success(a)

scala> res50.b
res52: scala.util.Try[String] = null

scala> new MyClass(b = Success("b"))
res53: MyClass = MyClass@68157e85

scala> res53.a
res54: scala.util.Try[String] = null

scala> res53.b
res55: scala.util.Try[String] = Success(b)
Brian
  • 20,195
  • 6
  • 34
  • 55
  • If an Object member is not set in the constructor, it defaults to `null`. – Paul Draper Sep 03 '13 at 18:23
  • You can use default arguments in the constructor. So that would become `class MyClass(val a: Try[String] = null, val b: Try[String] = null)`. I would discourage the use of `null` though. Look at the `Option` type or even just an empty `String`. – Brian Sep 03 '13 at 18:29
1

How about something closer to:

scala> def foo = ???
foo: Nothing

scala> :pa
// Entering paste mode (ctrl-D to finish)

case class Foo(a: String = Foo.afoo, b: String = Foo.bfoo)
object Foo {
import util._
def afoo = Try (foo) recover { case _ => "a" } get
def bfoo = Try (foo) recover { case _ => "b" } get
}

// Exiting paste mode, now interpreting.

warning: there were 2 feature warning(s); re-run with -feature for details
defined class Foo
defined object Foo

scala> Foo()
res0: Foo = Foo(a,b)
som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • Help me connect the dots...the example I had printed "Done" to std out when the constructor was finished (even if it threw an exception). – Paul Draper Sep 05 '13 at 01:24
  • The ctor can still do what it pleases, including printing Done. As the other comments suggest, the hard part is deciding which moving part should handle failure (or supply a default value, as here). It is maybe more idiomatic to do all that in a factory in the companion. You could add a method, too, that invokes apply and then reports done. What is done? Is the initializing method really a future? Maybe you want a factory that returns Try[Foo]. – som-snytt Sep 05 '13 at 04:43