The only doc I consult (when necessary) is the spec.
I agree that it is confusing. I find the previous innovations in Scala 2, and the further changes in Scala 3, interesting and exciting yet also intuitive – until I consult the reference.
I should emphasize that the methods on Java’s String are endlessly confusing to me. I consult the Javadoc whenever I am required to use the (terrible) API. Also, Spellcheck wants to amend Javadoc to avocado. That is the only time I will love spellcheck. Is there already a project named Javocado?
It’s late on a weekend, so I apologize in advance for a desultory answer, and also for using the word “desultory”.
I think I encounter this question mostly when using regex extractors. The regex is confusing to begin with, and how the unapplySeq interacts with pattern matching is additionally confusing.
This is clearly not the case. The unapplySeq ([sic]!) returns a seq of an empty string (see my comment about the API). The pattern matches, and the first is the empty string.
Sorry, I just ran out of steam. There are attempts to make regex pattern matches more amenable to pattern matches, using macros. For example, so that a failed match is None instead of null.
I’m not sure which version you are using and which messages you expect.
➜ snips cat unapply-seq.scala
object PathPartsOption:
def unapplySeq(s: String) = Some(s.split('/').toSeq)
object PathPartsBare:
def unapplySeq(s: String) = s.split('/').toSeq
@main
def demoPathParts() =
for path <- Array("one/two/three", "") do
println(s"With path = <${path}>")
val PathPartsOption(allOpt*) = path.runtimeChecked
val PathPartsOption(firstOpt, restOpt*) = path.runtimeChecked
println(s" Option first=<${firstOpt}> rest=${restOpt}")
println(s" Option first is empty: ${firstOpt.isEmpty} option: ${firstOpt.isInstanceOf[Option[String]]}, String=${firstOpt.isInstanceOf[String]}")
println(s" Option all=<${allOpt}>")
val PathPartsBare(allBare*) = path.runtimeChecked
val PathPartsBare(firstBare, restBare*) = path.runtimeChecked
println(s" Bare first=<${firstBare}> rest=${restBare}")
println(s" Bare first is empty: ${firstBare.isEmpty} option: ${firstBare.isInstanceOf[Option[String]]}, String=${firstBare.isInstanceOf[String]}")
println(s" Bare all=<${allBare}>")
println(s" Bare result=<${PathPartsBare.unapplySeq(path)}>")
➜ snips scala-cli run --server=false -S 3.8.4-RC2 unapply-seq.scala
-- Warning: /home/amarki/snips/unapply-seq.scala:15:69 -------------------------
15 | println(s" Option first is empty: ${firstOpt.isEmpty} option: ${firstOpt.isInstanceOf[Option[String]]}, String=${firstOpt.isInstanceOf[String]}")
| ^^^^^^^^
|this will always yield false since type String is not a subclass of class Option
-- Warning: /home/amarki/snips/unapply-seq.scala:21:68 -------------------------
21 | println(s" Bare first is empty: ${firstBare.isEmpty} option: ${firstBare.isInstanceOf[Option[String]]}, String=${firstBare.isInstanceOf[String]}")
| ^^^^^^^^^
|this will always yield false since type String is not a subclass of class Option
2 warnings found
With path = <one/two/three>
Option first=<one> rest=ArraySeq(two, three)
Option first is empty: false option: false, String=true
Option all=<ArraySeq(one, two, three)>
Bare first=<one> rest=ArraySeq(two, three)
Bare first is empty: false option: false, String=true
Bare all=<ArraySeq(one, two, three)>
Bare result=<ArraySeq(one, two, three)>
With path = <>
Option first=<> rest=ArraySeq()
Option first is empty: true option: false, String=true
Option all=<ArraySeq()>
Bare first=<> rest=ArraySeq()
Bare first is empty: true option: false, String=true
Bare all=<ArraySeq()>
Bare result=<ArraySeq()>
An extractor returning an empty sequence
object Empty:
def unapplySeq(s: String) = Nil
will compile but throw
val Empty(x, xs*) = ""
Edit: thanks for the opportunity to use sic and seq together in a sentence.