Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically wrap parameters in Options

Tags:

scala

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 nulls. 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?

like image 387
M4ks Avatar asked Apr 09 '15 13:04

M4ks


People also ask

How do I force text wrapping at the end of 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?

How do I wrap text in the label?

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.

How to wrap every parameter in a list in Python?

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.

How do I change the text in a parameter?

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.


3 Answers

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.

like image 131
Michael Zajac Avatar answered Sep 23 '22 08:09

Michael Zajac


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.

like image 28
mohit Avatar answered Sep 21 '22 08:09

mohit


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.

like image 42
vptheron Avatar answered Sep 21 '22 08:09

vptheron