docs.scala-lang icon indicating copy to clipboard operation
docs.scala-lang copied to clipboard

we do not have a method with name tailOption in the scala collections

Open robatipoor opened this issue 2 years ago • 4 comments

Written in this part of the scala3 book collections-methods

tail throws an java.lang.UnsupportedOperationException if the list is empty, so just like head and headOption, there’s also a tailOption method, which is preferred in functional programming.

But we do not have a method with name tailOption in the scala collections

robatipoor avatar Feb 28 '22 05:02 robatipoor

Hello, good catch! Would you be interested in contributing a fix?

julienrf avatar Feb 28 '22 09:02 julienrf

@julienrf Is this issue still relevant?? I see we have "last" and "lastOption" already defined which works just like "tail" and "tailOption".

mukesh210 avatar May 26 '22 17:05 mukesh210

@julienrf Is this issue still relevant?? I see we have "last" and "lastOption" already defined which works just like "tail" and "tailOption".

tailOption would return Option[Collection[T]] because it is the remaining collection with only the first element removed, or None for an empty collection. lastOption returns Option[T] because it is the last element of the collection, (which could be the first element for a singleton collection) or None for an empty collection

bishabosha avatar May 27 '22 08:05 bishabosha

The book should be fixed. The more convenient way, almost always, to do "tailOption" is to do drop(1). It doesn't cover every possible use case, but it covers enough so that the clutter of two more methods (tailOption and initOption) isn't worth it.

The few odd cases where you actually need tailOption should be handled with pipe instead, especially if you're using Scala 3 where you can define a fully efficient one:

extension [A](a: A)
  inline def pipe[B](inline f: A => B): B = f(a)

Any time you have an urge to write

someBigThingYouDontWantToRepeat.tailOption.map{ tail =>
  foo(tail)
}

you can choose one of the following excellent alternatives, and with the power of pipe you have many more options to do non-tailOptiony things, too.

someBigThingYouDontWantToRepeat.pipe{ xs =>
  if xs.isEmpty then None
  else Some(foo(xs.tail))
}

someBigThingYouDontWantToRepeat.pipe{ xs =>
  if xs.isEmpty then someDefault
  else foo(xs.tail)
}

someBigThingYouDontWantToRepeat.pipe{ xs =>
  xs.headOption{ head =>
    foo(head, xs.tail)
  }
}

someBigThingYouDontWantToRepeate.match{
  case head +: tail => foo(tail)
  case _ => someDefault
}

Ichoran avatar May 27 '22 16:05 Ichoran