scalapuzzlers / scalapuzzlers.github.com

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

Init you init me answers #90

Closed demobox closed 10 years ago

demobox commented 10 years ago

@dgruntz @nermin: What do you think..?

demobox commented 10 years ago

@nermin: ping..?

dgruntz commented 10 years ago

The idea behind this option was that a reader might have a (Java influenced) model in which by default all variables are first initialized with zero, and if you don't think too much a possible solution would be that adding 1 to both initial zeros leads to a value 1 for both objects.

Moreover, the answers are currently very symmetric (1, 2, both or an expression), and I like such symmetries.

In addition, as a puzzler solver I am not that much interested in whether a compile-time or a runtime exception is thrown on a particular puzzler, usually these are not the correct answers. I see your point that a runtime-exception might be a valuable option and propose to change the last option from fails with a compilation exception either to fails with a runtime exception or simply fails with an exception.

demobox commented 10 years ago

I see your point that a runtime-exception might be a valuable option and propose to change the last option from fails with a compilation exception either to fails with a runtime exception or simply fails with an exception.

Thanks for the feedback, @dgruntz! To be clear, I also liked the prints 1, it was just a matter of trying to choose the least likely one ;-)

Most other puzzlers differentiate between compilation and runtime exceptions, so I don't think we'd want to introduce a generic "fails with an exception here", but am happy to replace the compilation exception with the runtime one (which, incidentally, is actually what happens with two objects in a class, as discussed on scala-lang)

Question is: do we feel readers are more likely to think "it doesn't compile - perhaps Scala doesn't support circular definitions" vs. "it will print 1 - perhaps Scala doesn't bother initializing the other one for some reason and just returns the default value instead"? I think I as a reader would be more likely to eliminate the second option, but I agree that "does not compile" answers are boring. So am ultimately happy either way ;-)

@nermin: thoughts from you on this one..?

dgruntz commented 10 years ago

just realized that we already discussed this topic two years ago (how time passes!) in pull request #21. @nermin supported a proposal by @dgruntz to add 5 answers. And the user named @demobox proposed the answer "Fails with a compilation error or runtime exception"?. Finally the option "runtime exception" was dropped, but for me it would be fine to replace the compilation exception answer with the runtime exception one.

Btw, do you have statistics on which option is clicked most?

dgruntz commented 10 years ago

"it will print 1 - perhaps Scala doesn't bother initializing the other one for some reason and just returns the default value instead"?

you mean that the value fields of both XY.X.value and XY.Y.value are initialized with 1 (as I explained above).

But there could be another interpretation, namely that the field of the object accessed first is initialized with 1 (default value 0 + 1), and that the field of the object accessed second is initialized with 2, i.e. that the reader realizes that the order in which the objects are accessed is irrelevant but then makes the wrong choice.

demobox commented 10 years ago

And the user named @demobox proposed the answer "Fails with a compilation error or runtime exception"?

Tee hee hee. How time passes ;-) Statistics would be very interesting, but hard to collect in the current setup because users don't "vote" for a particular answer, they simply unhide the explanation. Nice feature suggestion, though!

namely that the field of the object accessed first is initialized with 1 (default value 0 + 1), and that the field of the object accessed second is initialized with 2

That's actually also what I meant - sorry, wasn't clear there. The reasoning would be something like:

  1. So I randomly choose to access XY.X.value first
  2. XY.X.value refers toXY.Y.value`. But that's not initialized yet, so we get the default value, 0
  3. If I later were to look at the other value, I would see 2

Question would be: in the second step, why would the system decide not to initialize the other value?

But, in any case, I think replacing "does not compile" is probably the less boring choice, too. Just waiting to hear what @nermin has to say...

dgruntz commented 10 years ago

Question would be: in the second step, why would the system decide not to initialize the other value?

it is difficult to explain the wrong models readers might have in their minds. An explanation could be that the value is only initialized if it is accessed directly using the (implicit) getter method and that probably the system accesses the field directly. I have tried to demonstrate such a model with the following implementation:

object XY {
    object X {
        var init: Boolean = false
        var value_ : Int = 0
        def value  : Int = { if(!init) { value_ = Y.value_ + 1; init= true }; value_ }
    }
    object Y {
        var init: Boolean = false
        var value_ : Int = 0
        def value  : Int = { if(!init) { value_ = X.value_ + 1; init= true }; value_ }
    }
}

The first accessed field now prints 1:

scala> XY.X.value
res0: Int = 1

scala> XY.Y.value
res1: Int = 2

scala> XY.X.value
res2: Int = 1
demobox commented 10 years ago

and that probably the system accesses the field directly

Ah, like that...bypassing the accessor. Naughty code! ;-)

I've updated the PR, in any case.

dgruntz commented 10 years ago

LGTM