Skip to content

Created puzzler: What's in a box. #127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Conversation

tbvh
Copy link

@tbvh tbvh commented Jun 24, 2015

Tricks you on a method '->', by application of the ArrowAssoc implicit conversion.
Probably works with 2.9.0 (and older), but tested on 2.11.4.

@demobox
Copy link
Collaborator

demobox commented Jun 25, 2015

@tbvh: Hi Tim

Thanks for this! I get the following when running this in the REPL:

scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Box(i: Int)

object Box {
  def ->(i: Int) = Box(i)
}
// Exiting paste mode, now interpreting.

defined class Box
defined object Box

scala> val myBox = new Box(5)
myBox: Box = Box(5)

scala> val yourBox = 5 -> Box
yourBox: (Int, Box.type) = (5,Box$@1e4c301d)

scala> val hisBox = Box -> 5
hisBox: Box = Box(5)

I'm guessing that's what your expecting. My main question is: what do you regard as the main element of the puzzler?

To me, the most potentially confusing line is val yourBox = 5 -> Box, because it's not clear why this compiles, unless there is another operator -> available that is not the one defined on Box. Do you think readers are likely to think this is also an application of Box.->? If so, how do you imagine a reader would come to that conclusion?

I'm asking because, if we think it's likely that the reader will either think that 5 -> Box does not compile, or that they will think that this is a different -> operator, it's not that strange that 5 -> Box returns something different from Box -> 5. As far as I'm understanding this, the difference between 5 -> Box and Box -> 5 is only really puzzling if you assume that it's the same operator.

@nermin: Your thoughts..?

@tbvh
Copy link
Author

tbvh commented Jun 25, 2015

Thanks for your reply.

I encountered this puzzle IRL, when I was looking at HList. I didn't really know about right binding methods at that time. As I was experimenting with them, I implemented them using -> instead of the :: method, and everything still compiled (well, for 2 elements). It didn't really occur to me that -> had some completely different effect.

On the other hand, I do understand your point, perhaps equallity is too obvious. I was looking for an operation on Tuple, that I could implement on Box, so that I could call the (apparent) Box method on my Tuple object and raise the confusion. But I didn't find an appropriate method, other that equals.
With your concern I can give it another try.

I have two suggestions

  1. I can change the constructor parameter to a val named x, and check equality of these fields. Tuple apparently also has an 'x' val defined, by another implicit.
  2. I can change the constructor parameter to a val named _1, and check equality of those fields (which would be equal).

For 1, equality would still fail, but we are accessing a member x on yourBox, which might add to the confusion.
For 2, equality would hold. However, by using a field _1 it might be hinting in the direction of Tuples too much.

Let me know what you think.

@demobox
Copy link
Collaborator

demobox commented Jun 26, 2015

@tbvh: Thank you for the update. Been a busy week here, but I hope to be able to get round to responding in the next couple of days.

Thanks for your patience! ;-)

@demobox
Copy link
Collaborator

demobox commented Jul 1, 2015

I have two suggestions

Thanks for the suggestions, @tbvh! As you also pointed out, the _1 option really looks like a tuple, so personally I think the other one is perhaps a bit better. Perhaps something along the following lines:

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Point(x: Int, y: Int)
object Point {
  def ->(x: Int, y: Int = 0) = apply(x, y)
}

// Exiting paste mode, now interpreting.

defined class Point
defined object Point

scala> println((5 -> Point).x == ((5, 0) -> Point).x)
(5,$line3.$read$$iw$$iw$Point$@3aa0c203)

with candidate answers such as "does not compile", "prints true", "prints false", "throws an exception" or so.

The reason I'm still in two minds about this is because it fundamentally relies on the fact that the reader simply doesn't know the -> operator and/or doesn't know the rules about right-associativity of operators. I wouldn't be surprised if there are plenty of Scala developers that fall into that category, but an unofficial rule for puzzlers is that they should not be "confusing just because you don't know Scala".

The fact that this actually compiles (because a tuple happens to have a value x) is, to me, the surprising element of this example, and I think that is something that would not be an expected bit of knowledge for a relatively proficient Scala developer. But I'd be interested to hear what @nermin, @som-snytt or @dgruntz have to say on that topic.

@som-snytt
Copy link
Contributor

Not very puzzling.

The day one of fast track to Scala has maps Map("Paris" -> "France") so basically everyone knows about arrow magic. It's how you learn what an implicit is.

But a puzzler on the DSL, 42 -> Box "put in a box" and val Box -> i = b "unbox it" which runs afoul of Predef implicits would be interesting.

Candidate implicits undergo overload resolution. Is there a way to make it prefer the Predef arrow conversion?

One can construct puzzlers like crosswords, but it's more fun to stumble across them IRL as the OP puts it.

@demobox
Copy link
Collaborator

demobox commented Jul 4, 2015

@tbvh Any thoughts on A.P. Marki's comments? I'm inclined to agree that we need to find a reason for the puzzler that is not just that users don't know about ->. They would either have to have good reason to assume that the default -> should not apply (but then, for some reason, it does), or that is does apply when, in fact, it does not.

@som-snytt: Thoughts on the following?

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Point(x: Int, y: Int)
object Point {
  def ->(xy: (Int, Int)) = apply(xy._1, xy._2)
}

// Exiting paste mode, now interpreting.

scala> println((Point -> 3 -> 5).x)
(($line34.$read$$iw$$iw$Point$@576be180,3),5)

I guess the associativity of the arrows shouldn't really be a surprise - the odd thing perhaps is this even compiles, i.e. that Tuple2 has a field x. Still, I'm not sure that's much of a "lesson learned."

@nermin: Your thoughts on this one..?

@som-snytt
Copy link
Contributor

@demobox That's pretty good. They've done work to stanch the members leaking in from implicits.

This is from Tuple2Zipped.Ops, and it's not even implicit class C(val x) extends AnyVal. It's just, Oops, should that be private?

Although it's kind of a bug, it's such a common occurrence that it's more of a syndrome. So that's a useful lesson. I wonder if IntelliJ tells you what introduced the member.

Actually, it's in the scaladoc:

http://www.scala-lang.org/files/archive/nightly/2.11.x/api/2.11.x/index.html#scala.Tuple2@x:%28T1,T2%29

I just fixed a bug with that -- oh yeah, it failed if the implicit took a by-name arg.

OK, why not, https://issues.scala-lang.org/browse/SI-9382

@tbvh
Copy link
Author

tbvh commented Jul 6, 2015

Thank you for this discussion.
I was just about to agree that the puzzle hinges too much on the lack of understanding about implicit ArrowAssoc (although I'm happy with the lessons I learned because of that). So I would have retracted my pull request.
Now that it became leverage to fix some leaky behaviour, I'm happy to hand it over to your merits.

I hope to be able to return one day with a valid puzzler. (For puzzlers sake of course, not to pick on Scala.)

@demobox
Copy link
Collaborator

demobox commented Jul 6, 2015

for puzzlers sake of course, not to pick on Scala

I suspect there's a conjecture in there somewhere that every Turing-complete language has puzzlers, or so ;-)

Thanks for sticking with this one, @tbvh - let's see what @nermin has to say!

@som-snytt
Copy link
Contributor

Next puzzlers presentation should have an animation depicting a dart board with a photo of Martin. When the audience is stumped, a dart lands dead center, bull's-eye. As more people answer correctly or groan at how stupid the puzzler is, the dart flies wider of the mark.

@demobox demobox mentioned this pull request Jul 26, 2015
@demobox
Copy link
Collaborator

demobox commented Jul 26, 2015

@tbvh: I've created an updated version based on the discussion here. Let's continue the discussion over at #131?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants