On many occasions I use parameters in form of the Option
with None
as default - like this:
def foo(bar:Option[String] = None)
This gets handy and allows me to easily omit null
s. However, if I do this, I need to change every invocation of the method to
foo(Some("bar"))
instead of simply
foo("bar")
This, however, looks a bit redundant, because it is obvious, that when I specify a value it is a full option. I'm pretty sure I can try to write some implicit converters to do such wrapping for me - unfortunately, I have no idea how.
Bonus - is this a sane thing to do? Is there any other way of dealing with a problem of "nullable" parameters?
You force text wrapping in the label to break at the end of parameters by checking this box. If not selected, text wraps at the first word reaching the boundary. Was this information helpful?
Otherwise, the text wraps within the label boundary. Wrap between parameters only. You force text wrapping in the label to break at the end of parameters by checking this box. If not selected, text wraps at the first word reaching the boundary.
Place your cursor in a parameter list. Press Ctrl +. to trigger the Quick Actions and Refactorings menu. Select Wrap every parameter to accept the refactoring. What: Lets you wrap binary expressions.
You can change how the place-holding text appears in the parameter. Suffix. You can add a suffix to the parameter value by adding a text string in this column. Break. You force a line break immediately after the parameter by checking this box. Otherwise, the text wraps within the label boundary. Wrap between parameters only.
I'll give you some options (pun intended).
Don't use an optional parameter, and instead use Option.apply
. This is useful for when the parameter isn't necessarily optional, but you want to deal with possible null
values being passed.
def foo(bar: String): ?? = Option(bar)... // operate on the Option[String]
The advantage of this is that Option.apply
automatically converts null
to None
for you, so there's absolutely no need to use if/else.
Use an overload for non-optional parameters. This is more so for when the parameter is truly optional, but gives you the convenience of passing Option
wrapped or unwrapped. It won't be possible to pass null
here without knowing the type first, however.
def foo(bar: String): ?? = foo(Option(bar))
def foo(bar: Option[String]): ?? = ???
Example:
def foo(bar: String): Option[String] = foo(Option(bar))
def foo(bar: Option[String]): Option[String] = bar.map(_ + "aaa")
scala> foo("bbb")
res7: Option[String] = Some(bbbaaa)
scala> foo(null: String) // The String ascription is necessary here.
res9: Option[String] = None
scala> val str: String = null
scala> foo(str) // No ascription necessary, since we know the type.
res10: Option[String] = None
Implicitly convert anything to Option
.
implicit def any2Opt[A](value: A): Option[A] = Option(value)
And keep the current definintion of
def foo(bar: Option[String]): ?? = ???
Implicitly converting to Option
, however can result in some unexpected results, so be wary.
You can write the desired generic implicit as
implicit def wrapToOption[T](x: T) = Option[T](x)
Then you can do
def foo(bar: Option[String] = None) = println(bar)
foo("bar") //> Some(bar)
foo() //> None
def fooBar(bar: Option[Int] = None) = println(bar)
fooBar(2) //> Some(2)
About it being sane thing to do, I will say no(personal opinion). Implicits are notoriously hard to debug. A logic gone wrong in the implicits can make your life hell.
Also, each new addition to the team will have to taught about all these "magics" happening behind the scenes.
It is a perfectly reasonable approach to set the type of your parameters to Option[_]
, if they really can be optional. However, I do not recommend using implicits to convert directly to Option[_]
.
You can make the syntax a little easier on the eye by including Scalaz and using some
:
foo("hello".some)
If you don't want to bring in Scalaz just for that it's very easy to write your own implicit to do so. This implicit is better because you explicitly call the some
method to "trigger" the implicit, as opposed to a "magical" conversion.
Another alternative, if you often call a function with parameters set to Some[_]
is to overload it (again, I'm not a fan of overloading either):
def foo(x: Option[String] = None, y: Option[Int] = None, z: Option[String] = None) { /* do stuff */ }
def foo(x: String, y: Int, z: Option[String] = None) = foo(x.some, y.some, z)
On a final note, I don't think there is anything wrong with wrapping your arguments in Some
if the function clearly defines them as optional. I wouldn't worry to much about this syntax.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With