scalapuzzlers / scalapuzzlers.github.com

Github Pages behind scalapuzzlers.com
www.scalapuzzlers.com
161 stars 53 forks source link

the sequence match puzzler #137

Closed yoeluk closed 9 years ago

demobox commented 9 years ago

Thanks for submitting this, @yoeluk and Razorfish team!

Just a heads-up that I'm travelling this and next week so I probably won't be able to look at this immediately, but will try to get round to this as soon as I can.

demobox commented 9 years ago

@yoeluk and team: nice! How about the following slight variation, which uses two different ways of getting a Seq from the Java list, and uses a method to make it a little more clear how you're likely to get hold of such a list in Scala code in the first place?

import java.util.{List => JList, LinkedList}
import scala.collection.JavaConversions._

def listFromJava: JList[Int] = {
  val jlist = new LinkedList[Int]()
  jlist.add(1)
  jlist.add(2)
  jlist
}

def printHeadOrEmpty(s: Seq[_]) = s match {
   case hd :: _ => println(hd)
   case _ => println("Empty :-(")
}

printHeadOrEmpty(listFromJava.toSeq) // Empty :-(
printHeadOrEmpty(Seq(listFromJava: _*)) // 1
yoeluk commented 9 years ago

Very nice @demobox ! I'll update the PR with your code. Just to give you a context we came across this when reading from a config file in an Akka application. It was hard to find the bug within a large application. Many thanks!

demobox commented 9 years ago

Just to give you a context we came across this when reading from a config file in an Akka application

Ah, thanks for explaining. Or should I say: "thank you Akka"? ;-)

Thanks also for updating the PR...

demobox commented 9 years ago

I was just taking a look at this again and noticed that it's not actually necessary to call

printHeadOrEmpty(listFromJava.toSeq)

since it's possible to simply pass the list in directly

scala> printHeadOrEmpty(listFromJava) // Empty :-(

On the other hand, there is more symmetry between listFromJava.toSeq and Seq(listFromJava) than between listFromJava and Seq(listFromJava).

That leaves us with three choices:

  1. Include all three variants in the puzzler
  2. Include listFromJava and Seq(listFromJava)
  3. Leave things as they are, i.e. listFromJava.toSeq and Seq(listFromJava)

@yoeluk What do you think..?

demobox commented 9 years ago

Also, I'm not sure the explanation is totally correct: from what I can see, the reason JavaConversions turns the Java list into a Buffer is because that is the only supported conversion to a (subtype of) Scala Seq.

If printHeadOrEmpty is declared to expect specifically an immutable Seq, the conversion does not work:

def printHeadOrEmpty(s: collection.immutable.Seq[_]) = s match {
   case hd :: _ => println(hd)
   case _ => println("Empty :-(")
}

scala> printHeadOrEmpty(listFromJava)
<console>:18: error: type mismatch;
 found   : java.util.List[Int]
 required: scala.collection.immutable.Seq[_]
              printHeadOrEmpty(listFromJava)
                               ^

But it does work if we specifically require a mutable Seq:

def printHeadOrEmpty(s: collection.mutable.Seq[_]) = s match {
   case hd +: _ => println(hd)
   case _ => println("Empty :-(")
}

scala> printHeadOrEmpty(listFromJava)
1
yoeluk commented 9 years ago

I totally agree! I think that we should include all three possibilities since it is nice to show the example with higher symmetry. Good find! I don't think the team checked the Scala sources of the JavaConversions, which was an oversight of course! I will update the PR as soon as I get a chance. Let me know if anything else comes to mind!

demobox commented 9 years ago

Let me know if anything else comes to mind!

Nothing for now - thanks for the response!

demobox commented 9 years ago

Merged to master: 6a30c18e3ce9cd81f7f747eae471006a0160cb79. See http://scalapuzzlers.com/#pzzlr-061.

Thanks @yoeluk and everyone on the Razorfish Scala team!!