Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option#orNull can't be used from java #11625

Open
mosesn opened this issue Jul 11, 2019 · 5 comments

Comments

Projects
None yet
5 participants
@mosesn
Copy link

commented Jul 11, 2019

I raised this issue before #10006, but the issue wasn't well enough specified, so it was closed. Let me try again.

Scala options are painful to use from java, and java users often want to simply use the actual value or a null, which is often idiomatic in java. In particular, tools like findbugs can even make this kind of programming somewhat pleasant. For java compatibility, it's very useful to be able to convert directly from an Option type to a "raw value or null" type. Option#orNull seems like it should be able to do this, but it can't. The bug here to me is that you can't unwrap your Option easily.

Here was the error message I got at the time:

error] class AllOf implements RoutePredicate {
                       [error] blahblaaablhablah.java:24: method orNull in class scala.Option<A> cannot be applied to given types;
                       [error]   required: scala.Predef.$less$colon$less<scala.runtime.Null$,A1>
                       [error]   found: no arguments
                       [error]   reason: cannot infer type-variable(s) A1
                       [error]     (actual and formal argument lists differ in length)
                       [error]     String sanitizedPath = opt.orNull();
                       [error] Compile failed at Oct 24, 2016 1:38:55 PM [0.221s]

               compile(blabhlahblahblahbl/predicates:predicates) failed: Zinc compile failed.

Someone suggested that users try Option#getOrElse(null) which will compile, but will result in a NPE if the else case is ever taken. The correct way of implementing it would be Option#getOrElse(() -> null), but this is easy to get wrong, allocates a function unnecessarily, and is surprising.

How about adding a method like Option#unsafeOrNull that doesn't ask for implicit evidence, and directly returns the contents of the Option in the Some case, and null in the None case?

@hrhino

This comment has been minimized.

Copy link
Member

commented Jul 11, 2019

We could keep orNull as it is, but not use the evidence parameter, so

def orNull(implicit ev: Null<:<A): A =
  if (isDefined) get else null.asInstanceOf[A]

which would allow opt.orNull(null) I guess, if we're OK with providing a slightly crusty API to Java (as we already often do).

I don't like unsafeOrNull. Arguably the code above (without the evidence) could be orZero, because Option.empty[Int].orZero would be 0, but they might not be obvious to most.

As a side note, () -> null should only allocate a single instance in Java, which will be cached at the callsite.

@Jasper-M

This comment has been minimized.

Copy link
Member

commented Jul 11, 2019

It's not the most convenient thing if all you want is just the bare value or null, but there's https://www.scala-lang.org/api/2.13.0/scala/jdk/javaapi/OptionConverters$.html now. I guess most Java users are used to inconvenient APIs 🙁

@lrytz

This comment has been minimized.

Copy link
Member

commented Jul 12, 2019

In larger mixed Scala-Java projects, there are maybe more issues of this kind, so I would expect there is some interop utility class. Is this a valid assumption? Writing a static orNull method in Java is quite simple.

I'm not saying we should ignore this issue, if there's a good way to fix it of course we have to do it. But the workaround doesn't seem too bad.

@ashawley

This comment has been minimized.

Copy link
Member

commented Jul 12, 2019

We could keep orNull as it is, but not use the evidence parameter

Wouldn't the implicit evidence parameter still cause it to not compile in Java?

Arguably the code above (without the evidence) could be orZero, because Option.empty[Int].orZero would be 0, but they might not be obvious to most.

This is because Int is a boxed primitive? For Java reference types it would be null, e.g. Option.empty[java.lang.Integer].orNull returns null, today, in Scala. Seems that would likely be the use case for Java client code.

@mosesn

This comment has been minimized.

Copy link
Author

commented Jul 16, 2019

@lrytz yes, that's true, but it also increases the burden of getting ramped up in these codebases. we want to expose APIs that are both scala-friendly and java-friendly, but when you encounter a scala Option and need to then go digging around for the appropriate helper to unwrap it for you, it's not very pleasant to use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.