Beginner question about "x match { case None => return; case Some( y ) => y.foo() }"

144 Aufrufe
Direkt zur ersten ungelesenen Nachricht

Saxo

ungelesen,
15.11.2012, 10:23:3515.11.12
an scala...@googlegroups.com
Hi,

I'm actually not into Scala. Maybe just not yet ;-). I saw a conversion in this thread on the Kotlin homepage:

http://confluence.jetbrains.net/display/Kotlin/Comparison+to+Scala

It is about writing


1. x match { case None => return; case Some( y ) => y.foo() }

or

2. return x.map( _.foo )

instead of just

3. 
if (x == null)
  return
x.foo()

This appeared a little weird to me. My question is whether chosing a solution as in 1. or 2. is normal Scala way of doing things or whether the position of that Scala developer in that thread is not the the rule. I'm just wondering. Maybe I'm not getting something. I believe some Scala developers would say "Scala is multi-paradigm and I prefer 3. Period.". But I'm curious here what some typical opinions are about this.

Regards, Oliver


"Ionuț G. Stan"

ungelesen,
15.11.2012, 10:41:0815.11.12
an scala...@googlegroups.com
For this particular example I'd go with another comment from that thread:

x.foreach(_.foo())

If you're returning nothing in the truthy branch of the third example,
it's obvious that x.foo() is a method called for its side-effects. So if
you only want some side-effects when something isn't null/None, then
foreach would be best. You can of course rewrite it as:

if (x != null) x.foo()

// or with Option

if (x.isDefined) x.get.foo()

I think any of these, or the `foreach` example is ok. I'd choose the
explicit null check if I were to work with a Java library and the null
comes from realms I don't have control over. This way I won't have to
wrap a value inside an Option for such a short period of time (i.e.
until I call `foo` on the wrapped value).

I'd definitely go with an Option when I want the API to signal a missing
value.

So, the least probable solution would be the one with explicit pattern
matching because Option already provides methods for most of the real
world patterns of usage.

--
Ionuț G. Stan | http://igstan.ro

Saxo

ungelesen,
15.11.2012, 11:36:1915.11.12
an scala...@googlegroups.com
Man, that is tough ... You just don't allow null to enter FP. I see, I see... So Scala is really FP with classes to organize your functional code. Imperative programming is eschewed in Scala. Have to mull this over for a while... ;-).

Thanks for the answer,
Oliver

Matthew Pocock

ungelesen,
15.11.2012, 12:49:1515.11.12
an Saxo, scala...@googlegroups.com
On 15 November 2012 16:36, Saxo <jet...@web.de> wrote:
Man, that is tough ... You just don't allow null to enter FP.

Well, it's more that you shouldn't allow null to enter any programming. They suck.

I see, I see... So Scala is really FP with classes to organize your functional code.

In FP, we can better represent optional or missing values using a type like Option. This type fits into a series of general design patterns that generalises applying functions to values in containers (map, flatMap, foreach, filter).
  
Imperative programming is eschewed in Scala. Have to mull this over for a while... ;-).

I'm not sure that functional/imperative is exactly the split, but I personally do try to structure my code so that I avoid side-effects as far as possible (things that return void/unit), use immutable values everywhere I can, and as far as sanity allows, use types to describe/enforce the desired behaviour.

If you take:

val x: Option[String]

This documents that x will contain an optional value that is a String. If you wanted to safely put that string into upper case, you can say:

val X = x map _.toUpper

If x was a String, then we'd say

val X = x.toUpper

So, there's minimal overhead to working with the raw String type and the optional String type when you are editing the code, and you've made it explicit that this value may be present or absent.

There are, as you've noticed, lots of ways to do this kind of job. Pick the one that you find easiest to read and write.

Matthew



--
Dr Matthew Pocock
Integrative Bioinformatics Group, School of Computing Science, Newcastle University
skype: matthew.pocock
tel: (0191) 2566550

Saxo

ungelesen,
15.11.2012, 13:23:2915.11.12
an scala...@googlegroups.com, Saxo
If x was a String, then we'd say
val X = x.toUpper

I see. Of course,  of course ...


There are, as you've noticed, lots of ways to do this kind of job. Pick the one that you find easiest to read and write.

Okay, that is some remark that leaves a more balanced idea in my head about all this.

Thanks a lot,
Oliver

Daniel Sobral

ungelesen,
15.11.2012, 18:34:2015.11.12
an Saxo, scala-user
It's not that different, but it isn't exactly how things are done. In idiomatic Scala, both null and they return keyword are generally avoided. I think the problem is mostly that the example is contrived, and without enough context to answer the question precisely.

So, the first question is whether you are returning some value or not. If you are returning some value, the option 1 is downright incorrect. It would typically be written like this:

x.map(_.foo()) // returns Some(x.get.foo()) if x.isDefined, or None if not.
x.map(_.foo()).getOrElse(z) // returns x.get.foo() is x.isDefined, or z if not
x match {
  case Some(y) => y.foo()
  case None      => None
}

If that code is *not* returning a value -- if it's being executed just for its side effects, then the code would likely read like this:

x.foreach(_.foo())
x match {
  case Some(y) => y.foo()
  case None      =>
}

*I* wouldn't use pattern matching in either case, but it happens to be faster than the alternatives, and lots of people just like it better. 

Now, if you have performance problems, you might resort to using null. But that's usually kept hidden -- Scala APIs that return or take nulls are very rare.
 

Regards, Oliver





--
Daniel C. Sobral

I travel to the future all the time.

Ziad Hatahet

ungelesen,
16.11.2012, 04:10:2916.11.12
an Daniel Sobral, scala-user
On Thu, Nov 15, 2012 at 3:34 PM, Daniel Sobral <dcso...@gmail.com> wrote:
Now, if you have performance problems, you might resort to using null. But that's usually kept hidden -- Scala APIs that return or take nulls are very rare.
 

Does Option[T] introduce that much overhead as to cause performance issues when used pervasively?


--
Ziad

Daniel Sobral

ungelesen,
16.11.2012, 06:53:3016.11.12
an Ziad Hatahet, scala-user
Option can slow down things in two ways:

1. It's another object, so we have two objects in the heap, without any locality of reference. Other effects, that I expect to be minor, are increased load due to extra allocations, and increased work on the garbage collector.

2. If you use foreach/map/etc, certain optimizations made by JIT are effectively disabled. There's also some penalty in the closure allocation. Note that you can use pattern matching instead, which avoids this problem.

These are not insurmountable problems, but they are problems right now. As compiler and JIT improves, it may go away. On the compiler side, the possibility of effectively optimizing Option with null pointers is within reach. The main problem is that Some(null) is valid, which would make it impossible to represent None as null. Lift framework allegedly depends on that. On the JIT side, optimization of megamorphic call sites has been pursued for a long time, but the addition of functions to Java will make this prolem a priority.

But, to answer your question strictly, Option does not introduce "that much" overhead. It introduces *overhead*. If you have a performance problem, then you need to decrease overhead.
 


--
Ziad

Matthew Pocock

ungelesen,
16.11.2012, 07:28:5916.11.12
an Ziad Hatahet, Daniel Sobral, scala-user
Hi,

Performance is only a problem in performance-critical code. In general, the safety that using Option[T] provides will save you a lot more development time than it will cost you run-time. If the code that touches Option[T] is outside of tight loops, it won't introduce any noticeable overhead at all.

I did have one case where a particular implementation of Map was boxing and unboxing a lot of values to and from Option when doing lookups, and where the map lookups where right inside a critical loop. In that case, it hurt me. However, it was obvious what was going on, and there was a work-around. Since then, I think that implementation has been fixed anyway. As the library, scala compiler and Java VM all are improved, the overhead of wrappers like Option[T] will continue to decrease without you needing to touch your source.

So, the short answer is that IMHO it's not worth worrying about performance with things like this unless you have problems with performance - it's more important to have clear and maintainable code. If your program is slow, then crack open a profiler and see why.

Matthew

Dennis Haupt

ungelesen,
16.11.2012, 08:01:0916.11.12
an Matthew Pocock, hat...@gmail.com, scala...@googlegroups.com, dcso...@gmail.com

-------- Original-Nachricht --------
> Datum: Fri, 16 Nov 2012 12:28:59 +0000
> Von: Matthew Pocock <turingate...@gmail.com>
> An: Ziad Hatahet <hat...@gmail.com>
> CC: Daniel Sobral <dcso...@gmail.com>, scala-user <scala...@googlegroups.com>
> Betreff: Re: [scala-user] Beginner question about "x match { case None => return; case Some( y ) => y.foo() }"

> Hi,
>
> Performance is only a problem in performance-critical code. In general,
> the
> safety that using Option[T] provides will save you a lot more development
> time than it will cost you run-time. If the code that touches Option[T] is
> outside of tight loops, it won't introduce any noticeable overhead at all.

100% agree. type safety has saved me so many times that i lost count.

>
> I did have one case where a particular implementation of Map was boxing
> and
> unboxing a lot of values to and from Option when doing lookups, and where
> the map lookups where right inside a critical loop. In that case, it hurt
> me. However, it was obvious what was going on, and there was a
> work-around.
> Since then, I think that implementation has been fixed anyway. As the
> library, scala compiler and Java VM all are improved, the overhead of
> wrappers like Option[T] will continue to decrease without you needing to
> touch your source.

>
> So, the short answer is that IMHO it's not worth worrying about
> performance
> with things like this unless you have problems with performance - it's
> more
> important to have clear and maintainable code. If your program is slow,
> then crack open a profiler and see why.

exactly. my strategy is not to worry about performance at all (just to try to pick a smart algorithm, it has a big effect compared to low level optimizations). this speeds up the development process and doesn't complicate my code. if there is a problem (which rarely happens) i can optimize it where it needs to be done. be lazy! work smart, not hard :)

nicola...@gmail.com

ungelesen,
16.11.2012, 08:28:3516.11.12
an Dennis Haupt, Matthew Pocock, hat...@gmail.com, Scala User, Daniel Sobral
100% agree. type safety has saved me so many times that i lost count.

The problem is that Option does not bring a lot of type safety as non-nullity (either null or Some null) is not checked at compile time.
So your program can type check and go wrong.

 

Seth Tisue

ungelesen,
16.11.2012, 08:33:0516.11.12
an scala...@googlegroups.com
On Fri, Nov 16, 2012 at 8:28 AM, nicola...@gmail.com
<nicola...@gmail.com> wrote:
> The problem is that Option does not bring a lot of type safety as
> non-nullity (either null or Some null) is not checked at compile time.

Disagree strongly. In practice, Option brings a great deal of type
safety. It's true that the null issue means it isn't perfect, but in
practice, it just isn't that hard to avoid using null at all in your
code. Nulls simply aren't a big issue for working Scala programmers.

We all look forward to a future in which null is ruled out at compile
time. But the present is actually already very good — much better than
the Option-less past.

--
Seth Tisue - se...@tisue.net - http://tisue.net

Alec Zorab

ungelesen,
16.11.2012, 08:35:5816.11.12
an Seth Tisue, scala-user
Option(null) returns None, so it certainly adds a veneer of respectability to the entire affair. As we seem to have to revisit every time we have one of these conversations, you can't (using either the kotlin based annotation approach or Option) actually guarantee non-nullity on the JVM anyway, so the question becomes: 

Which of these two tactics is more likely to stop NPEs?

I'd argue that building a culture where returning null is considered akin to spitting in someone's eye certainly helps reduce the problem. As ever, I offer the anecdata that I've seen less than a doezen NPEs in the last 6 months, all during development and all arising from initialisation order issues when I'm elbow deep in some cake pattern magic.

Daniel Sobral

ungelesen,
16.11.2012, 09:09:4516.11.12
an nicola...@gmail.com, Dennis Haupt, Matthew Pocock, Ziad Hatahet, Scala User
That's bs.

Option provides a way to REPLACE null. If you don't have nulls, you don't get NPE, and it's as simple as that.

Dennis Haupt

ungelesen,
16.11.2012, 09:19:5616.11.12
an nicola...@gmail.com, dcso...@gmail.com, scala...@googlegroups.com, hat...@gmail.com, turingate...@gmail.com
i don't return null or pass null as a parameter, so i never get null or Some(null) later

-------- Original-Nachricht --------
> Datum: Fri, 16 Nov 2012 13:28:35 +0000
> Von: "nicola...@gmail.com" <nicola...@gmail.com>
> An: Dennis Haupt <h-s...@gmx.de>
> CC: Matthew Pocock <turingate...@gmail.com>, hat...@gmail.com, Scala User <scala...@googlegroups.com>, Daniel Sobral <dcso...@gmail.com>
> Betreff: Re: [scala-user] Beginner question about "x match { case None => return; case Some( y ) => y.foo() }"

nicola...@gmail.com

ungelesen,
16.11.2012, 09:29:5316.11.12
an Dennis Haupt, Daniel Sobral, Scala User, hat...@gmail.com, Matthew Pocock
On Fri, Nov 16, 2012 at 2:19 PM, Dennis Haupt <h-s...@gmx.de> wrote:
i don't return null or pass null as a parameter, so i never get null or Some(null) later

It is somewhat akin to "I never do type error so I don't need a type checker." 
And usually you don't personally write all the code you run.

It is great to have Option, it would be even better if the policy was enforced by the type checker in some way.


Dennis Haupt

ungelesen,
16.11.2012, 09:44:4416.11.12
an nicola...@gmail.com, turingate...@gmail.com, hat...@gmail.com, scala...@googlegroups.com, dcso...@gmail.com
no, it's not. not passing null around is easy (in my own code). not making type errors is almost impossible.

-------- Original-Nachricht --------
> Datum: Fri, 16 Nov 2012 14:29:53 +0000
> Von: "nicola...@gmail.com" <nicola...@gmail.com>
> An: Dennis Haupt <h-s...@gmx.de>
> CC: Daniel Sobral <dcso...@gmail.com>, Scala User <scala...@googlegroups.com>, hat...@gmail.com, Matthew Pocock <turingate...@gmail.com>
> Betreff: Re: [scala-user] Beginner question about "x match { case None => return; case Some( y ) => y.foo() }"

Daniel Sobral

ungelesen,
16.11.2012, 11:23:0916.11.12
an nicola...@gmail.com, Dennis Haupt, Scala User, Ziad Hatahet, Matthew Pocock
There's a huge difference between the two. Writing "null" is a very conscious act, and checking against that is as easy as doing a grep. Scalastyle and IntelliJ, for that matter, produce warnings/errors (user's choice) for that.

But while checking for null "creation" is trivial, checking for improper null validation is not, and not checking for null is not a conscious act. So while what Scala offers doesn't make errors impossible, it does prevent them to a large extent.

And, yes, external code is a problem, particularly from Java. I don't know any Scala library which receives or returns null intentionally, except those wrapping Java libraries that work that way. Maybe there are examples, but they are not particularly common.

And, of course, when interfacing with Java you have to pay as much attention to what returns nulls as you would in Java, except that you can convert a nullable reference into an Option at the call site and forget about it elsewhere.

And that's why Option really makes NPE a non-problem: not only there are less nulls being passed, but anywhere you do get an NPE, all you have to do is refactor to use Option, and the compiler will tell guide you through the rest.

Geir Hedemark

ungelesen,
16.11.2012, 11:40:2916.11.12
an nicola...@gmail.com, Dennis Haupt, Matthew Pocock, hat...@gmail.com, Scala User, Daniel Sobral
Now, I understand how you get a null. But how do you manage to get a Some(null)? Won't Option(null) give you a None?

Geir


Kevin Wright

ungelesen,
16.11.2012, 12:03:2516.11.12
an Geir Hedemark, nicola...@gmail.com, Dennis Haupt, Matthew Pocock, hat...@gmail.com, Scala User, Daniel Sobral
Option(null) will, but you can explicitly create Some(null) or get it in a few other scenarios

e.g.

val m = Map(1->"a", 2 -> null)
m get 1 // returns Some("a")
m get 2 // returns Some(null)
m get 3 // returns None

Daniel Sobral

ungelesen,
16.11.2012, 12:03:5716.11.12
an Geir Hedemark, nicola...@gmail.com, Dennis Haupt, Matthew Pocock, Ziad Hatahet, Scala User
Option(null) == None
Some(null) == Some(null)

Simple. :-0

You might also start with a Some(v), then map something that turns v into a null.
 

Geir


Niels

ungelesen,
16.11.2012, 15:21:2716.11.12
an scala...@googlegroups.com, nicola...@gmail.com, Dennis Haupt, Ziad Hatahet, Matthew Pocock

I don't know any Scala library which receives or returns null intentionally, except those wrapping Java libraries that work that way. Maybe there are examples, but they are not particularly common.

 
I have one case where I deliberately use nulls in scala, though it's tightly controled. In the situation where I have a class with several arguments being Options of some type, I have created a companion object with an apply with default arguments where the default value is null. The apply method transforms the values into options. It makes writing some constructors a little bit easier. One can supply a value instead of Some(value). Other than that, I have not personally used a null, other than interfacing with Java.

Seth Tisue

ungelesen,
16.11.2012, 15:39:1416.11.12
an scala...@googlegroups.com
On Fri, Nov 16, 2012 at 9:29 AM, nicola...@gmail.com
<nicola...@gmail.com> wrote:
> It is great to have Option, it would be even better if the policy was
> enforced by the type checker in some way.

Everyone agrees on that.

But it's highly unclear how it would be achieved without impairing
either Java interop or performance or both.

--
Seth Tisue | Northwestern University | http://tisue.net
developer, NetLogo: http://ccl.northwestern.edu/netlogo/

Geir Hedemark

ungelesen,
16.11.2012, 16:27:3316.11.12
an Kevin Wright, nicola...@gmail.com, Dennis Haupt, Matthew Pocock, hat...@gmail.com, Scala User, Daniel Sobral
On 2012, Nov 16, at 6:03 PM, Kevin Wright wrote:
> Option(null) will, but you can explicitly create Some(null) or get it in a few other scenarios
>
> e.g.
>
> val m = Map(1->"a", 2 -> null)
> m get 1 // returns Some("a")
> m get 2 // returns Some(null)
> m get 3 // returns None

There you go. This is what I get for living too close to java-land.

Geir


Allen antworten
Antwort an Autor
Weiterleiten
0 neue Nachrichten