1

I am designing a program. I am new to Scala but it seems optional arguments are handled using the following:

def f1(my_string: Option[String] = None) = {

// Maybe do some pattern matching here to extract the value

}

However, for an end user this is pretty ugly as they will need to call this function like:

f1(Some("foo")

Is there a technique or pattern to turn this into:

f1("foo"))

and still work with an optional argument?i.e f1() also works?

The reason I ask is I have obviously used Scala libraries where adding an explicit Some(..) has not been necessary, but in their source code they have defined functions as above. I would personally use a default argument but wandering why this is a design pattern.

3
  • 1
    See my answer here as well as all the thread. Commented Jun 12, 2020 at 20:44
  • thanks that is exactly what I was looking for Commented Jun 12, 2020 at 20:56
  • I'm puzzled by the asymmetric parentheses in the two uses of f1 — typo? (I know nothing of Scala, so it may be obvious to an aficionado.) Commented Jul 25, 2022 at 14:16

3 Answers 3

4

An option is to create a helper class only for such arguments to avoid the anyToOption implicit conversion in the linked thread:

class OptArg[A](val asOption: Option[A])

object OptArg {
  def NoArg[A] = new OptArg[A](None)
  implicit def fromValue[A](x: A): OptArg[A] = new OptArg(Some(x))
  // optional
  implicit def toOption[A](arg: OptArg[A]) = arg.asOption
}

// use
def f1(my_string: OptArg[String] = NoArg) = {
  // can use my_string as if it was Option,
  // or call my_string.asOption explicitly
}

In simple cases of course overloading will be more suitable, but not if you have many optional arguments.

The drawback is relying on implicit conversions, but I think this one is pretty benign and unlikely to trigger accidentally.

OTOH I think it's quite rare in practice that an argument is optional but "no argument" doesn't correspond to some default value of that type, so I'd look if it can be defined as

def f1(my_string: String = something)

to avoid the whole problem.

Sign up to request clarification or add additional context in comments.

Comments

2

Instead of Option you could overload the method.

f1() :ReturnType = {...}

f1(arg:String) :ReturnType = {...}

2 Comments

Thanks @jwvh, just as a matter of interest, if I was working with a class instead, would the idiomatic way still be overloading the constructor?
In that case you probably want to use an auxiliary constructor. They have some restrictions but can be useful.
2

Syntactic cost of Option in calls such as

f1(Some("foo"))

is trivial as compared to the value of minimised risk of null pointer exceptions in a large codebase. Hoare, a Turing Awardee, appologised

I call it my billion-dollar mistake. It was the invention of the null reference in 1965.

1 Comment

But why compare it to that risk?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.