Is there is shorter way to this code?

30 views
Skip to first unread message

atta ur rehman

unread,
Jul 21, 2011, 1:10:03 PM7/21/11
to scala-user
Greetings all,

The method getUser() returns an Option[User] and I need to get a the lastName property or an alternative string value. Here is what I'm writing it as: 

  val user = getUser(); 

  

  val userName = user match {

    case Some(u) => user.lastName

    case _ => "No user found"

  }


I was just wondering if this is idiomatic Scala and if we can achieve the same result in fewer characters! 

Thanks.

ATTA

Garrett Rowe

unread,
Jul 21, 2011, 1:20:57 PM7/21/11
to atta ur rehman, scala...@googlegroups.com
Forgot to reply-all

On Thu, Jul 21, 2011 at 10:19 AM, Garrett Rowe <gmrow...@gmail.com> wrote:
> val username = user map (_.lastName) getOrElse "No user found"
>

√iktor Ҡlang

unread,
Jul 21, 2011, 1:49:46 PM7/21/11
to atta ur rehman, scala-user
On Thu, Jul 21, 2011 at 7:10 PM, atta ur rehman <attaur...@gmail.com> wrote:
Greetings all,

The method getUser() returns an Option[User] and I need to get a the lastName property or an alternative string value. Here is what I'm writing it as: 

  val user = getUser(); 

  

  val userName = user match {

    case Some(u) => user.lastName

    case _ => "No user found"

  }


This is the exact reason I'd like to have "fold" on Option so you could do this:

getUser.fold("No user found", _.lastName)
 
implicit def opt2foldable[T](o: Option[T]) = new { def fold[X](none: => X, some: (T) => X): X = o map some getOrElse none }

If you think that's terrible, you can go with:

getUser.map(_.lastName).getOrElse("No user found")


But in your use case you might want to go with:

getUser.toRight("No user found")
 
which gives you an Either[String, User]

Hope that helps!

Cheers,

 
I was just wondering if this is idiomatic Scala and if we can achieve the same result in fewer characters! 

Thanks.

ATTA



--
Viktor Klang

Akka Tech Lead
Typesafe - Enterprise-Grade Scala from the Experts

Twitter: @viktorklang

Sonnenschein

unread,
Jul 21, 2011, 2:07:19 PM7/21/11
to scala-user
Hi Atta,

what about

case class User(val lastName: String)
def getUser(exists: Boolean) = if (exists) Some(User("Atta")) else
None
val emptyUser = User("Not found")

val userName = getUser(true) getOrElse emptyUser lastName

See also http://blog.tmorris.net/scalaoption-cheat-sheet/

Cheers, Peter

atta ur rehman

unread,
Jul 21, 2011, 2:24:42 PM7/21/11
to √iktor Ҡlang, scala-user
Thanks, Viktor, that certainly helps. I get the idea of map and would lookup toRight but I'm too noob for 'fold' magic! 

> implicit def opt2foldable[T](o: Option[T]) = new { def fold[X](none: => X, some: (T) => X): X = o map some getOrElse none }

I hope you'll help me figure it out. So, here is what I understand. 

We are defining an implicit function that parameterized to T, accepts an Option. And then I get confused with the 'new' keyword! What it is that we're instantiating here? And whatever the type of object, it has another function in it called fold with parameterized as well and take two parameters! And I don't understad what's going on with none and some! 

Thanks again for your help. 

ATTA

2011/7/21 √iktor Ҡlang <viktor...@gmail.com>

atta ur rehman

unread,
Jul 21, 2011, 2:27:14 PM7/21/11
to Sonnenschein, scala-user
Thanks, Peter. 

Doesn't adding a boolean parameter to getUser() method pollutes the API? 

ATTA

Sonnenschein

unread,
Jul 21, 2011, 2:44:16 PM7/21/11
to scala-user
Hi again,
"exists: Boolean" was meant just for testing purposes.
Peter

atta ur rehman

unread,
Jul 21, 2011, 3:04:22 PM7/21/11
to Sonnenschein, scala-user
Thanks, Peter, I understand now!

Tony Morris

unread,
Jul 21, 2011, 5:02:49 PM7/21/11
to scala...@googlegroups.com

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 22/07/11 03:49, √iktor Ҡlang wrote:
> This is the exact reason I'd like to have "fold" on Option so you
> could do this:
>
> getUser.fold("No user found", _.lastName)

You do, it's just call map...getOrElse instead.

getUser map (_.lastName) getOrElse "No user found"

Remember, fold buys you nothing but syntax. It is no higher in
abstraction than pattern-matching. Its primary practical benefit would
be for its partial application. It is also useful for documentation --
reading a fold might give you the full algebra much easier than
reading case classes, etc.

- --
Tony Morris
http://tmorris.net/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk4ok/kACgkQmnpgrYe6r609jQCeKutm1tmiDp4x2ZPeIyxSQEed
0z4An292k/0fTb+T6HTsPEX7sXdsvw8s
=gJ6O
-----END PGP SIGNATURE-----

Naftoli Gugenheim

unread,
Jul 21, 2011, 6:41:48 PM7/21/11
to tmo...@tmorris.net, scala...@googlegroups.com


On Thu, Jul 21, 2011 at 5:02 PM, Tony Morris <tonym...@gmail.com> wrote:
fold buys you nothing but syntax

As opposed to?

Tony Morris

unread,
Jul 21, 2011, 7:28:58 PM7/21/11
to Naftoli Gugenheim, scala...@googlegroups.com
Abstraction by means of specialisation. A fold (unlike others) does not (by definition) specialise anything. As an example, for any ADT, you can write map using flatMap so long as your ADT is a pointed functor (A => F[A]):

def map[A, B](f: A => B): F[B] = flatMap(point compose f)

However, you can write *anything* in terms of fold (for any ADT). Don't believe me? Go and write the entire List API using foldRight or the entire Option API using only map and getOrElse. I promise you it can done -- it is also an extremely effective "bang for buck" exercise in my experiences teaching.

As I have pointed out many times before, a fold defines the algebra. You can even have fun with this fact yourself:

trait MyOption[A] {
  def fold[X](some: A => X, none: => X): X
}

MyOption ≈ Option.

As a practical consideration, you may exploit this fact in languages that don't have explicit ADTs like Scala does. Consider Javascript or C# -- you can encode Option using its fold, just like I did right there in Scala. This is not to say you necessarily should (in any language), but that you can without altering the algebraic representation.

Jim Balter

unread,
Jul 21, 2011, 8:41:37 PM7/21/11
to atta ur rehman, √iktor Ҡlang, scala-user
2011/7/21 atta ur rehman <attaur...@gmail.com>:

> Thanks, Viktor, that certainly helps. I get the idea of map and would lookup
> toRight but I'm too noob for 'fold' magic!
>> implicit def opt2foldable[T](o: Option[T]) = new { def fold[X](none: => X,
>> some: (T) => X): X = o map some getOrElse none }
>
> I hope you'll help me figure it out. So, here is what I understand.
> We are defining an implicit function that parameterized to T, accepts an
> Option. And then I get confused with the 'new' keyword! What it is that
> we're instantiating here?

An instance of an anonymous subclass (of Object, because no other
class was named after 'new') that has that fold[X](...) method.

> And whatever the type of object, it has another
> function in it called fold with parameterized as well and take two
> parameters! And I don't understad what's going on with none and some!

fold takes two parameters, what to do if `o` is None and what to do if
`o` is Some(a). They both must return the same type X, but it can be
any type. `none` is a lazy evaluation (that's the '=>') of a block,
and `some` is a function that takes a T -- the type of `a`, whatever
that is -- and returns an X. The implicit def means that fold can be
used as if it were a method of Option, so you can write
someOption.fold({ /* what to do if someOption is None */}, {a => /*
what to do with a if someOption is Some(a) */ })

The implementation -- o map some getOrElse none -- maps Some[T](a) to
Some[X](some(a)) and None[T] to None[X], then returns some(a) for the
Some case or none (the lazy evaluation finally occurs) for the None
case.

-- Jim

atta ur rehman

unread,
Jul 22, 2011, 4:23:31 AM7/22/11
to Jim Balter, √iktor Ҡlang, scala-user
Thank you very much, Jim. That was very helpful. 

Two more questions while we're on the topic. Firstly, named parameters and lazy evaluation (denoted by =>) are the same thing? 

Lastly, why do we need an anonymous object just for fold method? Couldn't we write a simple function -- the plain old implicit def a2b(...) -- to get the same effect? 

Thanks. 

ATTA 

√iktor Ҡlang

unread,
Jul 22, 2011, 5:51:20 AM7/22/11
to atta ur rehman, Jim Balter, scala-user
On Fri, Jul 22, 2011 at 10:23 AM, atta ur rehman <attaur...@gmail.com> wrote:
Thank you very much, Jim. That was very helpful. 

Two more questions while we're on the topic. Firstly, named parameters and lazy evaluation (denoted by =>) are the same thing? 

No, named parameters and lazy evaluation is completely separate things.

a call-by-name parameter, is evaluated every time it is dereferenced, ie:

scala> def foo(callMeByName: => String): String = callMeByName + callMeByName + callMeByName
foo: (callMeByName: => String)String

scala> foo({ println("pigdog"); "foo"})
pigdog
pigdog
pigdog
res0: String = foofoofoo

As you see "pigdog" is printed 3 times.
Now, the difference between "lazy" and call-by-name is that lazy will be evaluated 0..1 times and call-by-name 0..N times

Named parameters on the other hand is:

scala> def foo(awesome: Boolean, bippy: String) = if (awesome) Some(bippy) else None
foo: (awesome: Boolean, bippy: String)Option[String]

scala> foo(bippy = "pigdog", awesome = true)
res1: Option[String] = Some(pigdog)


As you can see, I can use the names of the parameters to specify theirs values, instead of their order in the declaration.

 

Lastly, why do we need an anonymous object just for fold method? Couldn't we write a simple function -- the plain old implicit def a2b(...) -- to get the same effect? 

The reason we need an anonymous object (but it might as well have been a named object, I was just trying to conserve space) is that Option does not have a "fold" method, so we need to have a method (opt2foldable) that can convert any Option[T] to something that has a "fold" method, which our anonymous object has.

Makes sense?

Cheers,

 

atta ur rehman

unread,
Jul 22, 2011, 6:37:05 AM7/22/11
to √iktor Ҡlang, Jim Balter, scala-user
Makes perfect sense, Viktor. Thanks. 

Just to make sure I have got it right on the named vs. call by name params: by default we can *always* call a function using it's parameters names instead of their order, like:

scala> def bazz(one: Int, two: Int) = two + one 
bazz: (one: Int,two: Int)Int

scala> bazz(two = 2, one = 1)
res0: Int = 3

I say always because you have to specify name and type for all the arguments to a function. 

Call-by-name, or lazy eval, on the other hand, forces evaluation on each dereferencing. And only difference between these two is => after the call-by-name argument. And the only reason I can think of having a call-by-name parameter is to let use pass a block of code that we want to execute only within our method. Lazily, that is. 

Have I finally nailed it? 

Thank you once again for sticking with a Scala noob! 

ATTA


2011/7/22 √iktor Ҡlang <viktor...@gmail.com>

Jim Balter

unread,
Jul 22, 2011, 6:40:18 AM7/22/11
to √iktor Ҡlang, atta ur rehman, scala-user
2011/7/22 √iktor Ҡlang <viktor...@gmail.com>:

>
>
> On Fri, Jul 22, 2011 at 10:23 AM, atta ur rehman <attaur...@gmail.com>
> wrote:
>>
>> Thank you very much, Jim. That was very helpful.
>> Two more questions while we're on the topic. Firstly, named parameters and
>> lazy evaluation (denoted by =>) are the same thing?
>
> No, named parameters and lazy evaluation is completely separate things.
>
> a call-by-name parameter, is evaluated every time it is dereferenced, ie:
>
> scala> def foo(callMeByName: => String): String = callMeByName +
> callMeByName + callMeByName
> foo: (callMeByName: => String)String
>
> scala> foo({ println("pigdog"); "foo"})
> pigdog
> pigdog
> pigdog
> res0: String = foofoofoo
>
> As you see "pigdog" is printed 3 times.
> Now, the difference between "lazy" and call-by-name is that lazy will be
> evaluated 0..1 times and call-by-name 0..N times

Yeah, sorry for the misuse of terminology. I should have said
call-by-name, which is evaluated on each occurrence, not "lazy"
(call-by-need), which is evaluated at most once. (Of course, in this
example `none` occurs only once so there's no difference in effect.)

-- Jim

Jim Balter

unread,
Jul 22, 2011, 6:47:22 AM7/22/11
to atta ur rehman, √iktor Ҡlang, scala-user
2011/7/22 atta ur rehman <attaur...@gmail.com>:

> Makes perfect sense, Viktor. Thanks.
> Just to make sure I have got it right on the named vs. call by name params:
> by default we can *always* call a function using it's parameters names
> instead of their order, like:
> scala> def bazz(one: Int, two: Int) = two + one
> bazz: (one: Int,two: Int)Int
> scala> bazz(two = 2, one = 1)
> res0: Int = 3
> I say always because you have to specify name and type for all the arguments
> to a function.
> Call-by-name, or lazy eval, on the other hand, forces evaluation on each
> dereferencing. And only difference between these two is => after the
> call-by-name argument. And the only reason I can think of having a
> call-by-name parameter is to let use pass a block of code that we want to
> execute only within our method. Lazily, that is.
> Have I finally nailed it?

Yes, except that lazy evaluation (as opposed to call-by-name)
technically means only evaluating upon the first dereference -- sorry
for leading you astray on that. Scala doesn't (yet) have lazy
parameters.

-- Jim

Andreas Scheinert

unread,
Jul 22, 2011, 6:49:09 AM7/22/11
to scala-user
hi All!
Ah! Inplenebtibg List API using fold? I remember that one was fun! =>
http://blog.tmorris.net/scala-exercises-for-beginners

Regards Andreas

On 22 Jul., 01:28, Tony Morris <tonymor...@gmail.com> wrote:
> On22/07/11 08:41, Naftoli Gugenheim wrote:
>
>
>
> > On Thu, Jul 21, 2011 at 5:02 PM, Tony Morris <tonymor...@gmail.com
> > <mailto:tonymor...@gmail.com>> wrote:
>
> >     fold buys you nothing but syntax
>
> > As opposed to?
>
> Abstraction by means of specialisation. A fold (unlike others) does not
> (by definition) specialise anything. As an example, for any ADT, you can
> write map using flatMap so long as your ADT is a pointed functor (A =>
> F[A]):
>
> def map[A, B](f: A => B): F[B] = flatMap(point compose f)
>
> However, you can write *anything* in terms of fold (for any ADT). Don't
> believe me? Go and write the entire List API using foldRight or the
> entire Option API using only map and getOrElse. I promise you it can
> done -- it is also an extremely effective "bang for buck" exercise in my
> experiences teaching.
>
> As I have pointed out many times before, a fold defines the algebra. You
> can even have fun with this fact yourself:
>
> trait MyOption[A] {
>   def fold[X](some: A => X, none: => X): X
>
> }
>
> MyOption ? Option.

√iktor Ҡlang

unread,
Jul 22, 2011, 6:50:11 AM7/22/11
to Jim Balter, atta ur rehman, scala-user
On Fri, Jul 22, 2011 at 12:47 PM, Jim Balter <J...@balter.name> wrote:
2011/7/22 atta ur rehman <attaur...@gmail.com>:
> Makes perfect sense, Viktor. Thanks.
> Just to make sure I have got it right on the named vs. call by name params:
> by default we can *always* call a function using it's parameters names
> instead of their order, like:
> scala> def bazz(one: Int, two: Int) = two + one
> bazz: (one: Int,two: Int)Int
> scala> bazz(two = 2, one = 1)
> res0: Int = 3
> I say always because you have to specify name and type for all the arguments
> to a function.
> Call-by-name, or lazy eval, on the other hand, forces evaluation on each
> dereferencing. And only difference between these two is => after the
> call-by-name argument. And the only reason I can think of having a
> call-by-name parameter is to let use pass a block of code that we want to
> execute only within our method. Lazily, that is.
> Have I finally nailed it?

Yes, except that lazy evaluation (as opposed to call-by-name)
technically means only evaluating upon the first dereference -- sorry
for leading you astray on that. Scala doesn't (yet) have lazy
parameters.

But you can emulate them using call-by-name and a lazy val:

def foo(soonToBeLazyParam: => String) {
  lazy val lazyParam = soonToBeLazyParam
  //Only use lazyParam below this line
}

I think it was someone on who suggested to add lazy (sugar for the above) to method parameters.
 

Kevin Wright

unread,
Jul 22, 2011, 6:52:58 AM7/22/11
to Jim Balter, atta ur rehman, √iktor Ҡlang, scala-user


Yes, except that lazy evaluation (as opposed to call-by-name)
technically means only evaluating upon the first dereference -- sorry
for leading you astray on that. Scala doesn't (yet) have lazy
parameters.

-- Jim


In most cases, you can get the same effect by assigning a by-name param to a lazy val at the very start of your class definition, and only use the val thereafter.

I say "most cases", because if you try this in a case class, then you still won't get the correct lazily-evaluated behaviour when using the generated extractor in a pattern match...

atta ur rehman

unread,
Jul 22, 2011, 7:05:37 AM7/22/11
to Kevin Wright, Jim Balter, √iktor Ҡlang, scala-user
Thank you all! It all has started to make sense! 

2011/7/22 Kevin Wright <kev.lee...@gmail.com>

john sullivan

unread,
Jul 22, 2011, 8:53:15 AM7/22/11
to Garrett Rowe, scala...@googlegroups.com
Wow, that's a nice trick that I haven't seen before and I'll definitely start using. Thanks everyone!
--
There are more things in heaven and earth, Horatio,
Than are dreamt of in your philosophy.

Kevin Wright

unread,
Jul 22, 2011, 8:56:24 AM7/22/11
to john sullivan, Garrett Rowe, scala...@googlegroups.com
There's also a variant on the theme for working with Java APIs that use and expect nulls:

    val output = Option(input) map {function} orNull

This works because the `Option(input)` construct will return None if input is null

--
Kevin Wright
mail: kevin....@scalatechnology.com
gtalk / msn : kev.lee...@gmail.com
vibe / skype: kev.lee.wright
steam: kev_lee_wright

"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra

Seth Tisue

unread,
Jul 22, 2011, 9:10:42 AM7/22/11
to scala-user
2011/7/22 √iktor Ҡlang <viktor...@gmail.com>:

> I think it was someone on who suggested to add lazy (sugar for the above) to
> method parameters.

If anyone wants to go vote for it and/or watch it, the ticket on this is
https://issues.scala-lang.org/browse/SI-240

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

Christopher Currie

unread,
Jul 22, 2011, 12:26:57 PM7/22/11
to Kevin Wright, john sullivan, Garrett Rowe, scala...@googlegroups.com
On Fri, Jul 22, 2011 at 5:56 AM, Kevin Wright <kev.lee...@gmail.com> wrote:
> There's also a variant on the theme for working with Java APIs that use and
> expect nulls:
>     val output = Option(input) map {function} orNull
> This works because the `Option(input)` construct will return None if input
> is null

That's a great tip, and will eliminate a grip of needlessly verbose
`match` statements in my code, thanks!

I've been learning the XML library and want to find a shorter way to express

(node \ "Subnode") match { case Seq(subnode) => Some(subnode); case
Seq() => None }

More generally, trying to convert a sequence of zero or one elements
into an Option. Any tips?

Christopher

Jim McBeath

unread,
Jul 22, 2011, 12:51:48 PM7/22/11
to Christopher Currie, scala...@googlegroups.com
node \ "Subnode" headOption

--
Jim

On Fri, Jul 22, 2011 at 09:26:57AM -0700, Christopher Currie wrote:
> Date: Fri, 22 Jul 2011 09:26:57 -0700
> From: Christopher Currie <chris...@currie.com>
> To: Kevin Wright <kev.lee...@gmail.com>
> Cc: john sullivan <sullym...@gmail.com>, Garrett Rowe
> <gmrow...@gmail.com>, scala...@googlegroups.com
> Subject: Re: [scala-user] Is there is shorter way to this code?

AGYNAMIX Torsten Uhlmann

unread,
Jul 21, 2011, 1:25:21 PM7/21/11
to scala-user
Hi Garrett,

you could write:

scala> case class User(val first: String, val last: String) {}
defined class User

scala> val a=User("Fritz", "Fuchs")
a: User = User(Fritz,Fuchs)

scala> val b = Option(a)
b: Option[User] = Some(User(Fritz,Fuchs))

scala> b map(_.last) getOrElse ("No")
res0: String = Fuchs

How about that?

Torsten.

-- 
AGYNAMIX(R). Passionate Software.
Inh. Torsten Uhlmann | Buchenweg 5 | 09380 Thalheim
Phone:       +49 3721 273445
Fax:             +49 3721 273446
Mobile:       +49 151 12412427
Web:           http://www.agynamix.de

Reply all
Reply to author
Forward
0 new messages