scalapuzzlers / scalapuzzlers.github.com

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

038 Sharp Corner Cases #80

Closed som-snytt closed 11 years ago

som-snytt commented 11 years ago

When does A not match A? It's a corner case.

My first draft was simpler, see below.

I juiced it slightly because of the "baby announcement" theme, hopes for the "future" and all that. "It's a 7!" doesn't mean anything.

But having two cases is harder to reason about and suggests traps about the basic mechanics of the pattern match (case order, whatever), instead of how ClassTag is used. WDYT?

class C[A: ClassTag] {
  def announce(f: Future[A]) = f onSuccess {
    case a: A => Console println s"It's a $a!"
  }
}
demobox commented 11 years ago

@som-snytt Thanks for this one. Sorry, bit full up with work this week - will have a look at this asap!

som-snytt commented 11 years ago

@demobox That's ok with me, but you will kick yourself if you encounter this behaviour and lose an hour (or more!) debugging. ;)

som-snytt commented 11 years ago

I'm not sure if this is already covered somewhere, but after answering a question on SO, seeing a wrong answer up-voted, commenting the error, finally down-voting and, naturally, suffering the retaliatory down-vote, I realized that maybe it's more fun and less work to ask questions. So I posted a puzzler.

http://stackoverflow.com/q/17648064/1296806

Unfortunately, one of the smarties was online instead of getting some sleep on a school night and he answered right away. That's like somebody shouting out the answer at a puzzlers session.

Needless to say, not a great one, but this was funny:

I already been reading all use of _ and all 17 ways eacj fail to make 17000 Scala questions.
som-snytt commented 11 years ago

OK, that was embarrassing. I swear I wasn't just looking at puzzlers. It was:

http://stackoverflow.com/q/17639922/1296806

So I take back my previous comment, it's a great puzzler.

The ongoing confusion on SO is not so much about block evaluation, but things like "when do I need parens?", which really requires you to recognize a block expression when you see it.

Hey, I just noticed that you get +2 for accepting an answer on SO, which exactly balances the -2 retaliatory downvotes on that other answer. Now I'm going to log out of SO forever and never be annoyed again.

I'll get my puzzlers elsewhere! The old-fashioned way, on the lists! and my own stupidity!

demobox commented 11 years ago

I'm guessing this requires 2.11? Gives a compile error in 2.10.0:

scala> new C().announce(future(7))
<console>:18: error: this type parameter must be specified
              new C().announce(future(7))
              ^
som-snytt commented 11 years ago

Improved type inference strikes again.

I'll move the future value param to the constructor, so it works on 2.10.

Possibly it even looks better that way.

som-snytt commented 11 years ago

Better title?

som-snytt commented 11 years ago

This one reads like a puzzler! DelayedInit might be too annoying to work as a real puzzler, though. The nice part is that it dovetails with @paulp's one-question faq.

https://issues.scala-lang.org/browse/SI-7677

The issue tracker should have an automated system that requires everyone from userland to read and answer correctly every puzzler before submitting a new issue. Maybe you should create an issue for that.

demobox commented 11 years ago

Ah, so

new C(future(7: java.lang.Integer)).announce()

would match. Based on your original comment, I almost think the version you proposed there:

class Expect[A: ClassTag](f: Future[A]) {
  def announce() = f onSuccess {
    case a: A      => Console println s"It's a $a"
  }
}

is more puzzling, but less attractive since the messages are not as fun. I can imagine the reasoning here going:

With the two-case variant, I think there's no real reason to assume the String one won't match, so the remaining question is what happens to the Int one, in which case the String invocation becomes a bit redundant.

Turning the cases around changes things a little:

class Expect[A: ClassTag](f: Future[A]) {
  def announce() = f onSuccess {
    case size: A      => Console println s"It weighs $size lbs."
    case what: String => Console println s"It's a $what!"
  }
}

because in this case the String will (confusingly?) actually be matched by the first clause. That means the real output isn't quite as nice, but does allow for some nice choices, e.g.

  1. Prints "It's a boy"..."It weighs 7 lbs."
  2. Prints "It's a boy"
  3. Prints "It weighs boy lbs."..."It weighs 7 lbs."
  4. Prints "It weighs boy lbs."
som-snytt commented 11 years ago

OK, let's go back to just one case. I could lose the cute.

There was that misspelling in an issue, excepted for expected. That's pretty funny, maybe.

som-snytt commented 11 years ago

OK, as usual, the ongoing edit is better. Why is that?

I didn't add to the message, "...as excepted!" because it's not that funny.

Maybe I can use that gag in a puzzler about exceptions. "Expect the Unexcepted."

This edit includes supplying the boxed type in the answer.

demobox commented 11 years ago

I like! Thanks for the edits, @som-snytt!

@nermin: your thoughts on this one? Planning to merge this weekend if you're good...

demobox commented 11 years ago

See http://scalapuzzlers.com/#pzzlr-038. Thanks, @som-snytt!