Expand Messages
• Haskell Bowling Ron Jeffries 11/01/2006 At the Simple Design and Testing conference, Dan Mead bravely agreed to implement the infamous Bowling Game exercise,
Message 1 of 23 , Nov 2, 2006
Ron Jeffries
11/01/2006

At the Simple Design and Testing conference, Dan Mead bravely
agreed to implement the infamous Bowling Game exercise, TDD style,
in Haskell. It was fun and interesting. Here I present some
discussion, his program, and a Java program in a similar style.

Ron Jeffries
www.XProgramming.com
Here is Edward Bear, coming downstairs now, bump, bump, bump, on the back
of his head. It is, as far as he knows, the only way of coming downstairs,
but sometimes he feels that there really is another way, if only he could
stop bumping for a moment and think of it. And then he feels that perhaps
there isn't. -- A. A. Milne
• ... While I had to study the Haskell for a moment in order to understand it, your Java equivalent is hideous, IMHO. Modifying the rolls member by calling
Message 2 of 23 , Nov 3, 2006
Ron Jeffries <ronjeffries@...> writes:

> Ron Jeffries
> 11/01/2006
>
> At the Simple Design and Testing conference, Dan Mead bravely
> agreed to implement the infamous Bowling Game exercise, TDD style,
> in Haskell. It was fun and interesting. Here I present some
> discussion, his program, and a Java program in a similar style.
>

While I had to study the Haskell for a moment in order to understand it, your
Java "equivalent" is hideous, IMHO.

Modifying the rolls member by calling setRemainingRolls prior to the recursive
score() call strikes me as really strange. For starters, it relies on
thisFrameScore being called before remainingScore, which I know /is/
guaranteed in Java, but still strikes me as "scary", since it means that the +
on that return in score() is not commutative. Secondly it means that rolls is
consumed as the score is calculated, so at the end of the "recursion", rolls
just contains the last frame, which is strange.

In fact, having a whole data member "rolls" just to store the internal state
of the score() function strikes me as really rather bizarre.

For a recursive approach in Java, I would expect something like the following
--- pass the rolls in to the constructor, and leave it unmodified,
constructing new game instances for the recursive call.

Note, this is untested, as I don't have a Java compiler on this machine.

public class BowlingGame {
final List<Integer> rolls;

public BowlingGame(Integer[] rollsArray) {
rolls = Arrays.asList(rollsArray);
}

public BowlingGame(List<Integer> rolls_) {
rolls = rolls_;
}

public Integer score() {
if (rolls.size() == 0) return 0;
if (rolls.size() == 3) return thisFrameScore();
return thisFrameScore() + new BowlingGame(remainingRolls()).score();
}

private List<Integer> remainingRolls() {
return rolls.subList(frameSize(), rolls.size());
}

private Integer thisFrameScore() {
Integer frameScore = 0;
for (Integer roll : thisFramesRolls())
frameScore += roll;
return frameScore;
}

private List<Integer> thisFramesRolls() {
return rolls.subList(0, numberOfRollsToScore());
}

private int numberOfRollsToScore() {
return (isMark()) ? 3: 2;
}

private boolean isMark() {
return isStrike() || isSpare();
}

private boolean isStrike() {
return rolls.get(0) == 10;
}

private boolean isSpare() {
return rolls.get(0) + rolls.get(1) == 10;
}

private int frameSize() {
return isStrike()? 1: 2;
}
}

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• Hello, Anthony. On Friday, November 3, 2006, at 12:00:53 PM, you ... That seems somewhat harsh, but you could be right. Certainly it s not an implementation
Message 3 of 23 , Nov 3, 2006
Hello, Anthony. On Friday, November 3, 2006, at 12:00:53 PM, you
wrote:

> While I had to study the Haskell for a moment in order to understand it, your
> Java "equivalent" is hideous, IMHO.

That seems somewhat harsh, but you could be right. Certainly it's
not an implementation I'd normally recommend, but it adheres as
closely as I could figure out to the Haskell one, which was my
intention.

> Modifying the rolls member by calling setRemainingRolls prior to the recursive
> score() call strikes me as really strange.

Interesting. I'm not troubled at all with an object that creates a
list and then consumes it. Tell us more about why that bothers you?

> For starters, it relies on
> thisFrameScore being called before remainingScore, which I know /is/
> guaranteed in Java, but still strikes me as "scary", since it means that the +
> on that return in score() is not commutative. Secondly it means that rolls is
> consumed as the score is calculated, so at the end of the "recursion", rolls
> just contains the last frame, which is strange.

I did it that way because in the Haskell implementation the list
gets smaller and smaller. And if the order were somehow reversed,
the tests wouldn't run, so I'm not terribly worried about that. I
note that your implementation below will probably run with the
statements in either order, which is nice.

> In fact, having a whole data member "rolls" just to store the internal state
> of the score() function strikes me as really rather bizarre.

Yes ... however I see no alternative if the code is to match what
the Haskell does, which does it all inside the recursive code.

> For a recursive approach in Java, I would expect something like the following
> --- pass the rolls in to the constructor, and leave it unmodified,
> constructing new game instances for the recursive call.

One could. That seems to me not to match the Haskell very well,
which is recurring in code, but not so much by creating new
instances ...

> Note, this is untested, as I don't have a Java compiler on this machine.

I didn't test it either, but it's an interesting implementation, and
certainly looks as if it'll work.

It deviates a bit further from the Haskell code than I wanted to,
but it avoids having the state variable, if that's something one
wanted to do. I'm not troubled by an object that consumes a
collection that belongs to it, though I'd rather have it being
consumed in the method. When I wrote it that way, which I did before
getting to the current version, all the methods then had to be
passed the list, which made for lots of parameters. Given that
position, I preferred the member variable.

> public class BowlingGame {
> final List<Integer> rolls;
>
> public BowlingGame(Integer[] rollsArray) {
> rolls = Arrays.asList(rollsArray);
> }

> public BowlingGame(List<Integer> rolls_) {
> rolls = rolls_;
> }

> public Integer score() {
> if (rolls.size() == 0) return 0;
> if (rolls.size() == 3) return thisFrameScore();
> return thisFrameScore() + new
> BowlingGame(remainingRolls()).score();
> }
>
> private List<Integer> remainingRolls() {
> return rolls.subList(frameSize(), rolls.size());
> }

> private Integer thisFrameScore() {
> Integer frameScore = 0;
> for (Integer roll : thisFramesRolls())
> frameScore += roll;
> return frameScore;
> }

> private List<Integer> thisFramesRolls() {
> return rolls.subList(0, numberOfRollsToScore());
> }

> private int numberOfRollsToScore() {
> return (isMark()) ? 3: 2;
> }

> private boolean isMark() {
> return isStrike() || isSpare();
> }
>
> private boolean isStrike() {
> return rolls.get(0) == 10;
> }

> private boolean isSpare() {
> return rolls.get(0) + rolls.get(1) == 10;
> }

> private int frameSize() {
> return isStrike()? 1: 2;
> }
> }

Thanks for the suggestion ... may I add it to the article, or a
second one, crediting you?

Ron Jeffries
www.XProgramming.com
Questioner: How do I sell my executive team on doing this stuff?
Jim Highsmith: Don't. Just do it. They don't know what you're doing anyway.
• ... Sorry. On re-reading my comment, I agree that it sounds harsh. ... Then your understanding of the Haskell one is quite different from mine. I would think
Message 4 of 23 , Nov 3, 2006
Ron Jeffries <ronjeffries@...> writes:

> Hello, Anthony. On Friday, November 3, 2006, at 12:00:53 PM, you
> wrote:
>
>> While I had to study the Haskell for a moment in order to understand it, your
>> Java "equivalent" is hideous, IMHO.
>
> That seems somewhat harsh, but you could be right.

Sorry. On re-reading my comment, I agree that it sounds harsh.

> Certainly it's
> not an implementation I'd normally recommend, but it adheres as
> closely as I could figure out to the Haskell one, which was my
> intention.

Then your understanding of the Haskell one is quite different from mine. I
would think the Haskell one was closest to:

class BowlingGame
{
public static score(List<Integer> rolls)
{
if(rolls.size()==0) return 0;
if(rolls.size()==1) return rolls.get(0);
if(rolls.size()==2) return rolls.get(0) + rolls.get(1);
if(rolls.size()==3) return rolls.get(0) + rolls.get(1) + rolls.get(2);
if(rolls.get(0)==10)
return rolls.get(0)+ rolls.get(1) + rolls.get(2) +
score(rolls.subList(1,rolls.size()));
else if((rolls.get(0) + rolls.get(1))==10)
return rolls.get(0) + rolls.get(1) + rolls.get(2) +
score(rolls.subList(2,rolls.size()));
else return rolls.get(0) + rolls.get(1) +
score(rolls.subList(2,rolls.size()));
}
}

>> Modifying the rolls member by calling setRemainingRolls prior to the recursive
>> score() call strikes me as really strange.
>
> Interesting. I'm not troubled at all with an object that creates a
> list and then consumes it. Tell us more about why that bothers you?

It's an instance of the Temporary Field smell from Refactoring, p84.

>> For starters, it relies on
>> thisFrameScore being called before remainingScore, which I know /is/
>> guaranteed in Java, but still strikes me as "scary", since it means that the +
>> on that return in score() is not commutative. Secondly it means that rolls is
>> consumed as the score is calculated, so at the end of the "recursion", rolls
>> just contains the last frame, which is strange.
>
> I did it that way because in the Haskell implementation the list
> gets smaller and smaller. And if the order were somehow reversed,
> the tests wouldn't run, so I'm not terribly worried about that. I
> note that your implementation below will probably run with the
> statements in either order, which is nice.
>
>> In fact, having a whole data member "rolls" just to store the internal state
>> of the score() function strikes me as really rather bizarre.
>
> Yes ... however I see no alternative if the code is to match what
> the Haskell does, which does it all inside the recursive code.

Indeed --- it does a recursive call to self, /passing/ a smaller list to the
recursive call. Being a functional language, Haskell doesn't actually modify
the list, so the list itself doesn't get any smaller.

>> For a recursive approach in Java, I would expect something like the following
>> --- pass the rolls in to the constructor, and leave it unmodified,
>> constructing new game instances for the recursive call.
>
> One could. That seems to me not to match the Haskell very well,
> which is recurring in code, but not so much by creating new
> instances ...

I guess that depends on how you look at it. The Haskell certainly doesn't
modify it's list, either.

>> Note, this is untested, as I don't have a Java compiler on this machine.
>
> I didn't test it either, but it's an interesting implementation, and
> certainly looks as if it'll work.
>
> It deviates a bit further from the Haskell code than I wanted to,
> but it avoids having the state variable, if that's something one
> wanted to do. I'm not troubled by an object that consumes a
> collection that belongs to it, though I'd rather have it being
> consumed in the method. When I wrote it that way, which I did before
> getting to the current version, all the methods then had to be
> passed the list, which made for lots of parameters. Given that
> position, I preferred the member variable.

I can see the argument for it being a member variable, and I think it's a
better place than passing round the list everywhere. I think Fowler's
suggested refactoring of extracting a method object (to fix the Temporary
Field smell) gets us to a better place, which is essentially what I did with
my code.

> Thanks for the suggestion ... may I add it to the article, or a
> second one, crediting you?

Of course.

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• Hello, Anthony. On Friday, November 3, 2006, at 5:54:08 PM, you ... The version I published is equivalent to that one, with the repeated mentions of subList
Message 5 of 23 , Nov 3, 2006
Hello, Anthony. On Friday, November 3, 2006, at 5:54:08 PM, you
wrote:

>> Certainly it's
>> not an implementation I'd normally recommend, but it adheres as
>> closely as I could figure out to the Haskell one, which was my
>> intention.

> Then your understanding of the Haskell one is quite different from mine. I
> would think the Haskell one was closest to:

> class BowlingGame
> {
> public static score(List<Integer> rolls)
> {
> if(rolls.size()==0) return 0;
> if(rolls.size()==1) return rolls.get(0);
> if(rolls.size()==2) return rolls.get(0) + rolls.get(1);
> if(rolls.size()==3) return rolls.get(0) + rolls.get(1) + rolls.get(2);
> if(rolls.get(0)==10)
> return rolls.get(0)+ rolls.get(1) + rolls.get(2) +
> score(rolls.subList(1,rolls.size()));
> else if((rolls.get(0) + rolls.get(1))==10)
> return rolls.get(0) + rolls.get(1) + rolls.get(2) +
> score(rolls.subList(2,rolls.size()));
> else return rolls.get(0) + rolls.get(1) +
> score(rolls.subList(2,rolls.size()));
> }
> }

The version I published is equivalent to that one, with the repeated
mentions of subList and rolls factored out. I started from one that
looked like that, except that I left out the ifs that didn't matter.

Let's look. The published version:

private Integer score() {
if (rolls.size() == 0) return 0;
if (rolls.size() == 3) return thisFrameScore();
return thisFrameScore() + remainingScore();
}

The size 1 and 2 don't really occur. thisFrameScore is:

private Integer thisFrameScore() {
Integer frameScore = 0;
for (Integer roll : thisFramesRolls())
frameScore += roll;
return frameScore;
}

which is either rolls.get(0)+rolls.get(1) or
rolls.get(0)+rolls.get(1)+rolls.get(2), depending on whether the
frame is a strike or spare. So that method removes the duplication
from all the references to rolls.get(x) in the version you showed
above.

Then I didn't like the occurrences of all the sublist stuff, so I
reused the thisFrameScore, and removed the duplication of the
recursive call in the single method remainingScore, which does all
the sublisting and then calls back to score.

The version you show is just a couple or duplication removals away
from the one I show.

Maybe I /should/ have gone my usual way and shown all the steps. ;->

Ron Jeffries
www.XProgramming.com
I cannot find my duck.
• Hello, Anthony. On Friday, November 3, 2006, at 5:54:08 PM, you ... I would say not. This is the /only/ field in the class, making it equivalent to the class
Message 6 of 23 , Nov 3, 2006
Hello, Anthony. On Friday, November 3, 2006, at 5:54:08 PM, you
wrote:

>> Interesting. I'm not troubled at all with an object that creates a
>> list and then consumes it. Tell us more about why that bothers you?

> It's an instance of the Temporary Field smell from Refactoring, p84.

I would say not. This is the /only/ field in the class, making it
equivalent to the class that Martin would extract if there were
other, non-temp fields in there. It would certainly be possible to
do yet another extract class, but I don't see the point of that.

>>> In fact, having a whole data member "rolls" just to store the internal state
>>> of the score() function strikes me as really rather bizarre.

Well, think about what you'd get if you extracted a class as Martin
suggests ... you'd get the class we have here.
>>
>> Yes ... however I see no alternative if the code is to match what
>> the Haskell does, which does it all inside the recursive code.

> Indeed --- it does a recursive call to self, /passing/ a smaller list to the
> recursive call. Being a functional language, Haskell doesn't actually modify
> the list, so the list itself doesn't get any smaller.

Yes, true. I didn't like all those duplicate calls to sublist, and
all the parms, so I decided to truncate the real list. Unwound, it
looks like the version you just posted. I find this one easier to
understand in that it isn't such intricate code. YMMV of course.

>>> For a recursive approach in Java, I would expect something like the following
>>> --- pass the rolls in to the constructor, and leave it unmodified,
>>> constructing new game instances for the recursive call.
>>
>> One could. That seems to me not to match the Haskell very well,
>> which is recurring in code, but not so much by creating new
>> instances ...

> I guess that depends on how you look at it. The Haskell certainly doesn't
> modify it's list, either.

Absolutely true. If I had had cleaner sublisting, like a Ruby slice,
I'd perhaps not have gone this way. But Java doesn't help us much in
that regard.

> I can see the argument for it being a member variable, and I think it's a
> better place than passing round the list everywhere. I think Fowler's
> suggested refactoring of extracting a method object (to fix the Temporary
> Field smell) gets us to a better place, which is essentially what I did with
> my code.

You refer here to your original version. I agree, creating the
separate instance is nice. I got where I got going a different path,
so that extraction didn't occur to me, and since I just have the one
member variable and don't mind consuming it, I didn't feel a push to
go there. I'd not argue, though, that your version isn't better --
it might be. Certainly would be for some folks.

world's noisiest coffee shop, and I've got an idea for another way
to do this that might be interesting. Maybe I'll work on it over the
weekend ...

Thanks,

Ron Jeffries
www.XProgramming.com
I'm giving the best advice I have. You get to decide whether it's true for you.
• ... OK. ... Maybe. It might have been clearer than just showing an equivalent Java program . ... I disagree here. If the last frame is open, score() will be
Message 7 of 23 , Nov 4, 2006
Ron Jeffries <ronjeffries@...> writes:

> Hello, Anthony. On Friday, November 3, 2006, at 5:54:08 PM, you
> wrote:
>
>>> Certainly it's
>>> not an implementation I'd normally recommend, but it adheres as
>>> closely as I could figure out to the Haskell one, which was my
>>> intention.
>
>> Then your understanding of the Haskell one is quite different from mine. I
>> would think the Haskell one was closest to:
>
>> class BowlingGame
>> {
>> public static score(List<Integer> rolls)
>> {
>> if(rolls.size()==0) return 0;
>> if(rolls.size()==1) return rolls.get(0);
>> if(rolls.size()==2) return rolls.get(0) + rolls.get(1);
>> if(rolls.size()==3) return rolls.get(0) + rolls.get(1) + rolls.get(2);
>> if(rolls.get(0)==10)
>> return rolls.get(0)+ rolls.get(1) + rolls.get(2) +
>> score(rolls.subList(1,rolls.size()));
>> else if((rolls.get(0) + rolls.get(1))==10)
>> return rolls.get(0) + rolls.get(1) + rolls.get(2) +
>> score(rolls.subList(2,rolls.size()));
>> else return rolls.get(0) + rolls.get(1) +
>> score(rolls.subList(2,rolls.size()));
>> }
>> }
>
> The version I published is equivalent to that one, with the repeated
> mentions of subList and rolls factored out. I started from one that
> looked like that, except that I left out the ifs that didn't matter.

OK.

Further down, you wrote:
> Maybe I /should/ have gone my usual way and shown all the steps. ;->

Maybe. It might have been clearer than just showing "an equivalent Java
program".

> Let's look. The published version:
>
> private Integer score() {
> if (rolls.size() == 0) return 0;
> if (rolls.size() == 3) return thisFrameScore();
> return thisFrameScore() + remainingScore();
> }
>
> The size 1 and 2 don't really occur.

I disagree here. If the last frame is open, score() will be called with rolls
containing two elements. It will score correctly, since remainingScore will
then call score with an empty list, and thisFrameScore will correctly use only
two elements, but the case does occur, and it seems a bit strange to recurse
on that case and not the case of the final frame being a bonus frame. That
said, it works, and it's fewer lines here, so it could be argued that it's
simpler.

> The version you show is just a couple or duplication removals away
> from the one I show.

Maybe. I just didn't like it ;-)

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• ... OK, I m going to work through this. First up, the first 4 if s just sum the whole list, so let s deal with that: private static Integer sum(List
Message 8 of 23 , Nov 4, 2006
Ron Jeffries <ronjeffries@...> writes:

> Hello, Anthony. On Friday, November 3, 2006, at 5:54:08 PM, you
> wrote:
>
>> class BowlingGame
>> {
>> public static score(List<Integer> rolls)
>> {
>> if(rolls.size()==0) return 0;
>> if(rolls.size()==1) return rolls.get(0);
>> if(rolls.size()==2) return rolls.get(0) + rolls.get(1);
>> if(rolls.size()==3) return rolls.get(0) + rolls.get(1) + rolls.get(2);
>> if(rolls.get(0)==10)
>> return rolls.get(0)+ rolls.get(1) + rolls.get(2) +
>> score(rolls.subList(1,rolls.size()));
>> else if((rolls.get(0) + rolls.get(1))==10)
>> return rolls.get(0) + rolls.get(1) + rolls.get(2) +
>> score(rolls.subList(2,rolls.size()));
>> else return rolls.get(0) + rolls.get(1) +
>> score(rolls.subList(2,rolls.size()));
>> }
>> }

OK, I'm going to work through this.

First up, the first 4 "if"s just sum the whole list, so let's deal with that:

private static Integer sum(List<Integer> rolls)
{
Integer total = 0;
for (Integer roll : rolls)
total += roll;
}

public static int score(List<Integer> rolls)
{
if(rolls.size()<=3) return sum(rolls);
if(rolls.get(0)==10)
return rolls.get(0)+ rolls.get(1) + rolls.get(2) +
score(rolls.subList(1,rolls.size()));
else if((rolls.get(0) + rolls.get(1))==10)
return rolls.get(0) + rolls.get(1) + rolls.get(2) +
score(rolls.subList(2,rolls.size()));
else return rolls.get(0) + rolls.get(1) +
score(rolls.subList(2,rolls.size()));
}

Next up: the if/else if/else chain is essentially "score for this frame" +
score for remainder, so lets do that.

public static int score(List<Integer> rolls)
{
if(rolls.size()<=3) return sum(rolls);
else return thisFrameScore(rolls) + score(remainingRolls(rolls));
}

private static int thisFrameScore(List<Integer> rolls)
{
if(rolls.get(0)==10)
return rolls.get(0)+ rolls.get(1) + rolls.get(2);
else if((rolls.get(0) + rolls.get(1))==10)
return rolls.get(0) + rolls.get(1) + rolls.get(2);
else return rolls.get(0) + rolls.get(1);
}

private static List<Integer> remainingRolls(List<Integer> rolls)
{
if(rolls.get(0)==10)
return rolls.subList(1,rolls.size())
else return rolls.subList(2,rolls.size());
}

remainingRolls is an easy target, so let's do that next:

private static List<Integer> remainingRolls(List<Integer> rolls)
{
return rolls.subList(rollsInThisFrame(rolls),rolls.size())
}

private static boolean isStrike(List<Integer> rolls)
{
return rolls.get(0)==10;
}
private static int rollsInThisFrame(List<Integer> rolls)
{
return isStrike(rolls)?1:2
}

thisFrameScore has plentiful duplication. First strikes and spares are the same:

private static int thisFrameScore(List<Integer> rolls)
{
if(isStrike(rolls) || isSpare(rolls))
return rolls.get(0)+ rolls.get(1) + rolls.get(2);
else return rolls.get(0) + rolls.get(1);
}

private static boolean isSpare(List<Integer> rolls)
{
return (rolls.get(0)+rolls.get(1))==10;
}

We're still not done with thisFrameScore:

private static int thisFrameScore(List<Integer> rolls)
{
return sum(rolls.subList(0,scoringRollsThisFrame(rolls)));
}

private static int scoringRollsThisFrame(List<Integer> rolls)
{
return (isStrike(rolls) || isSpare(rolls))?3:2;
}

That looks good for now. The only thing left is the rolls parameter, which is
a real pain to pass round; besides all those static methods are a smell,
too. Here's all the current code:

class BowlingGame
{
public static int score(List<Integer> rolls)
{
if(rolls.size()<=3) return sum(rolls);
else return thisFrameScore(rolls) + score(remainingRolls(rolls));
}

private static Integer sum(List<Integer> rolls)
{
Integer total = 0;
for (Integer roll : rolls)
total += roll;
}

private static List<Integer> remainingRolls(List<Integer> rolls)
{
return rolls.subList(rollsInThisFrame(rolls),rolls.size())
}

private static boolean isStrike(List<Integer> rolls)
{
return rolls.get(0)==10;
}
private static int rollsInThisFrame(List<Integer> rolls)
{
return isStrike(rolls)?1:2;
}

private static boolean isSpare(List<Integer> rolls)
{
return (rolls.get(0)+rolls.get(1))==10;
}

private static int thisFrameScore(List<Integer> rolls)
{
return sum(rolls.subList(0,scoringRollsThisFrame(rolls)));
}

private static int scoringRollsThisFrame(List<Integer> rolls)
{
return (isStrike(rolls) || isSpare(rolls))?3:2;
}
}

If we make rolls a member, then we get:

class BowlingGame
{
// utility method, really belongs elsewhere
private static Integer sum(List<Integer> rolls)
{
Integer total = 0;
for (Integer roll : rolls)
total += roll;
}

final List<Integer> rolls;
public BowlingGame(List<Integer> rolls_)
{
rolls=rolls_;
}
public static int score(List<Integer> rolls)
{
return new BowlingGame(rolls).score();
}
public int score()
{
if(rolls.size()<=3) return sum(rolls);
else return thisFrameScore() + score(remainingRolls());
}

private List<Integer> remainingRolls()
{
return rolls.subList(rollsInThisFrame(),rolls.size())
}

private boolean isStrike()
{
return rolls.get(0)==10;
}
private int rollsInThisFrame()
{
return isStrike()?1:2;
}

private boolean isSpare()
{
return (rolls.get(0)+rolls.get(1))==10;
}

private int thisFrameScore()
{
return sum(rolls.subList(0,scoringRollsThisFrame()));
}

private int scoringRollsThisFrame()
{
return (isStrike() || isSpare())?3:2;
}
}

which is pretty much what my code looked like yesterday.

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• ... The point in doing so would be to make it simpler. Yes, rolls is the only field, but that doesn t make it OK to use it as a general scratch area for
Message 9 of 23 , Nov 4, 2006
Ron Jeffries <ronjeffries@...> writes:

> Hello, Anthony. On Friday, November 3, 2006, at 5:54:08 PM, you
> wrote:
>
>>> Interesting. I'm not troubled at all with an object that creates a
>>> list and then consumes it. Tell us more about why that bothers you?
>
>> It's an instance of the Temporary Field smell from Refactoring, p84.
>
> I would say not. This is the /only/ field in the class, making it
> equivalent to the class that Martin would extract if there were
> other, non-temp fields in there. It would certainly be possible to
> do yet another extract class, but I don't see the point of that.

The point in doing so would be to make it simpler. Yes, rolls is the only
field, but that doesn't make it OK to use it as a general "scratch area" for
passing data between functions. That's my real gripe with that --- you're
passing parameters by modifiying member data. It's no different to:

class Foo
{
int flag;

public void bar()
{
flag=123;
baz();
}

public void wibble()
{
flag=27;
baz();
}

public void baz()
{
if(flag==27)
{
// ...
}
else if(flag==123)
{
// ...
}
else
{
// ...
}
}
}

>>>> In fact, having a whole data member "rolls" just to store the internal state
>>>> of the score() function strikes me as really rather bizarre.
>
> Well, think about what you'd get if you extracted a class as Martin
> suggests ... you'd get the class we have here.

Not quite. See my other post, where I work through it. YMMV, I guess.

>> Indeed --- it does a recursive call to self, /passing/ a smaller list to the
>> recursive call. Being a functional language, Haskell doesn't actually modify
>> the list, so the list itself doesn't get any smaller.
>
> Yes, true. I didn't like all those duplicate calls to sublist, and
> all the parms, so I decided to truncate the real list. Unwound, it
> looks like the version you just posted. I find this one easier to
> understand in that it isn't such intricate code. YMMV of course.

My single-function solution was just a direct port of the Haskell; I didn't
expect it to be clearer than the expanded Java, but it /is/ where I expected
you to start from.

> Absolutely true. If I had had cleaner sublisting, like a Ruby slice,
> I'd perhaps not have gone this way. But Java doesn't help us much in
> that regard.

Thanks for the discussion,

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• Hello, Anthony. On Saturday, November 4, 2006, at 5:39:03 AM, you ... Yes. I had just been fiddling and wound up where I was, and thought that the Haskell
Message 10 of 23 , Nov 4, 2006
Hello, Anthony. On Saturday, November 4, 2006, at 5:39:03 AM, you
wrote:

> Further down, you wrote:
>> Maybe I /should/ have gone my usual way and shown all the steps. ;->

> Maybe. It might have been clearer than just showing "an equivalent Java
> program".

Yes. I had just been fiddling and wound up where I was, and thought
that the Haskell version and the experience with Dan was worth
writing about. Might do it again ... except why bother? Guess I
won't know unless I try ...

>> Let's look. The published version:
>>
>> private Integer score() {
>> if (rolls.size() == 0) return 0;
>> if (rolls.size() == 3) return thisFrameScore();
>> return thisFrameScore() + remainingScore();
>> }
>>
>> The size 1 and 2 don't really occur.

> I disagree here. If the last frame is open, score() will be called with rolls
> containing two elements. It will score correctly, since remainingScore will
> then call score with an empty list, and thisFrameScore will correctly use only
> two elements, but the case does occur, and it seems a bit strange to recurse
> on that case and not the case of the final frame being a bonus frame. That
> said, it works, and it's fewer lines here, so it could be argued that it's
> simpler.

Ah. I went the other way. Normally I'd expect a recursive solution
to include /only/ the empty list case. For example, a recursion
tends to end on some degenerate case, like factorial ending with
0 -> 1.

So I wanted /only/ the 0 to represent a special case. The Haskell
pattern-matching code unfortunately requires dealing with 2
elements, because otherwise there'll be an extra recursion on final
bonus frames. So the size == 3 is actually a hack that is there to
support that oddity, and I'd think it wouldn't [shouldn't] occur.

The case of 1 item, as far as I can tell, cannot really occur, so I
definitely wouldn't list it.

>> The version you show is just a couple or duplication removals away
>> from the one I show.
>
> Maybe. I just didn't like it ;-)

That's cool. What's interesting to me is exploring why we like or
don't like things. The differences are where we learn, it seems to
me.

Ron Jeffries
www.XProgramming.com
The rules are ways of thinking, not ways to avoid thinking.
• Hello, Anthony. On Saturday, November 4, 2006, at 6:12:59 AM, you ... Cool! Fun, isn t it? Ron Jeffries www.XProgramming.com Inigo Montoya: You are wonderful!
Message 11 of 23 , Nov 4, 2006
Hello, Anthony. On Saturday, November 4, 2006, at 6:12:59 AM, you
wrote:

> OK, I'm going to work through this.

Cool! Fun, isn't it?

Ron Jeffries
www.XProgramming.com
Inigo Montoya: You are wonderful!
Man in Black: Thank you. I have worked hard to become so.
• ... Yes. I wouldn t bother otherwise. Anthony -- Anthony Williams Software Developer Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Message 12 of 23 , Nov 4, 2006
Ron Jeffries <ronjeffries@...> writes:

> Hello, Anthony. On Saturday, November 4, 2006, at 6:12:59 AM, you
> wrote:
>
>> OK, I'm going to work through this.
>
> Cool! Fun, isn't it?

Yes. I wouldn't bother otherwise.

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• Hello, Anthony. On Saturday, November 4, 2006, at 6:22:06 AM, you ... I agree that it s using the member field to avoid the parameter (and the duplication),
Message 13 of 23 , Nov 4, 2006
Hello, Anthony. On Saturday, November 4, 2006, at 6:22:06 AM, you
wrote:

>>> It's an instance of the Temporary Field smell from Refactoring, p84.
>>
>> I would say not. This is the /only/ field in the class, making it
>> equivalent to the class that Martin would extract if there were
>> other, non-temp fields in there. It would certainly be possible to
>> do yet another extract class, but I don't see the point of that.

> The point in doing so would be to make it simpler. Yes, rolls is the only
> field, but that doesn't make it OK to use it as a general "scratch area" for
> passing data between functions. That's my real gripe with that --- you're
> passing parameters by modifiying member data. It's no different to:

> class Foo
> {
> int flag;

> public void bar()
> {
> flag=123;
> baz();
> }

> public void wibble()
> {
> flag=27;
> baz();
> }

> public void baz()
> {
> if(flag==27)
> {
> // ...
> }
> else if(flag==123)
> {
> // ...
> }
> else
> {
> // ...
> }
> }
> }

I agree that it's using the member field to avoid the parameter (and
the duplication), and that's arguably bad. I don't agree that it's
the same as your example, since in the bowling version the member
variable is the only state for the object, and essentially every
method references it. Not to mention the if statements, and the
general meaninglessness of the flag variable. In your example,
there's an idea waiting to be discovered. In the Java example ...
not so much.

I do like your version better, why weren't you here pairing with me?

Would you, as a rule, have all your member variables invariant over
the lifetime of your objects? I've seen people argue in favor of
that, but state changes need to live somewhere, and on the call
stack isn't always my favorite place.

>>>>> In fact, having a whole data member "rolls" just to store the internal state
>>>>> of the score() function strikes me as really rather bizarre.
>>
>> Well, think about what you'd get if you extracted a class as Martin
>> suggests ... you'd get the class we have here.

> Not quite. See my other post, where I work through it. YMMV, I guess.

Well, one wouldn't /inevitably/ get the same class, though your
result looks terribly close to mine to the naked eye. I didn't
compare them side by side. Maybe I'll refactor mine back to look
more like yours ... time and interest permitting of course.

>>> Indeed --- it does a recursive call to self, /passing/ a smaller list to the
>>> recursive call. Being a functional language, Haskell doesn't actually modify
>>> the list, so the list itself doesn't get any smaller.
>>
>> Yes, true. I didn't like all those duplicate calls to sublist, and
>> all the parms, so I decided to truncate the real list. Unwound, it
>> looks like the version you just posted. I find this one easier to
>> understand in that it isn't such intricate code. YMMV of course.

> My single-function solution was just a direct port of the Haskell; I didn't
> expect it to be clearer than the expanded Java, but it /is/ where I expected
> you to start from.

And I did start there, just didn't show the work. Would probably
have been better if I had.

>> Absolutely true. If I had had cleaner sublisting, like a Ruby slice,
>> I'd perhaps not have gone this way. But Java doesn't help us much in
>> that regard.

True. The version I had had just too much nested function calling in
it to be readable, IMO, so I went the way I went, wound up with
something I could live with, because I don't mind my member
variables holding variable state. Perhaps that's an evil I should

I'm writing a second article now and will include some of your
earlier comments ... I don't think I can do the whole discussion
justice, but I'll do what I can.

Thanks,

Ron Jeffries
www.XProgramming.com
Reason is and ought only to be the slave of the passions. -- David Hume
• ... Soon 2 years will have passed since someone explained to you what the infamous Bowling Game might look like in a functional programming language, but
Message 14 of 23 , Nov 4, 2006
--- In extremeprogramming@yahoogroups.com, Ron Jeffries
<ronjeffries@...> wrote:
>
> Ron Jeffries
> 11/01/2006
>
> At the Simple Design and Testing conference, Dan Mead bravely
> agreed to implement the infamous Bowling Game exercise, TDD style,
> in Haskell. It was fun and interesting. Here I present some
> discussion, his program, and a Java program in a similar style.
>

Soon 2 years will have passed since someone explained to you what "the
infamous Bowling Game" might look like in a functional programming
language, but that was in a newsgroup discussion not on stage :-)

I seem to remember learning about recursive functions 30 years ago, in
the second week of a Pascal programming course, so it's a little
puzzling to me that a software developer would say "Recursive methods
tend to be confusing, in my opinion."
• Hello, Isaac. On Saturday, November 4, 2006, at 9:13:38 PM, you ... Isaac, I feel sure that had you noticed the fatal defect in Dan s original Haskell, and the
Message 15 of 23 , Nov 4, 2006
Hello, Isaac. On Saturday, November 4, 2006, at 9:13:38 PM, you
wrote:

> I seem to remember learning about recursive functions 30 years ago, in
> the second week of a Pascal programming course, so it's a little
> puzzling to me that a software developer would say "Recursive methods
> tend to be confusing, in my opinion."

Isaac, I feel sure that had you noticed the fatal defect in Dan's
original Haskell, and the Ruby and Java programs based on it, you'd
have gleefully reported it here. Yet, with your 30 years of
experience in recursion, you did not. Recursive algorithms do not
give up their secrets easily.

I wrote my first recursions in the early sixties, wrote a Master's
thesis on the topic, and have written recursive algorithms in a
dozen or more languages.

And yes, I say that they tend to be confusing.

Ron Jeffries
www.XProgramming.com
Look to the master; Follow the master; Walk with the master;
See through the master; Become the master. -- Modern Zen Poem
• ... I m afraid I haven t read his program or your program. I knew that you d already seen the pattern-matching bowling game programs I wrote in Clean - so I
Message 16 of 23 , Nov 4, 2006
--- In extremeprogramming@yahoogroups.com, Ron Jeffries
<ronjeffries@...> wrote:
>
> Hello, Isaac. On Saturday, November 4, 2006, at 9:13:38 PM, you
> wrote:
>
> > I seem to remember learning about recursive functions 30 years ago, in
> > the second week of a Pascal programming course, so it's a little
> > puzzling to me that a software developer would say "Recursive methods
> > tend to be confusing, in my opinion."
>
> Isaac, I feel sure that had you noticed the fatal defect in Dan's
> original Haskell, and the Ruby and Java programs based on it, you'd
> have gleefully reported it here. Yet, with your 30 years of
> experience in recursion, you did not. Recursive algorithms do not
> give up their secrets easily.
>

I'm afraid I haven't read his program or your program. I knew that
you'd already seen the pattern-matching bowling game programs I wrote
in Clean - so I chose to gleefully remind you of those working programs.

> I wrote my first recursions in the early sixties, wrote a Master's
> thesis on the topic, and have written recursive algorithms in a
> dozen or more languages.
>
> And yes, I say that they tend to be confusing.

Good for you!

I always find proving loop-termination conditions rather gnarly but no
one says iterative algorithms are confusing just because they mess up
the termination condition.
• ... There s a large stretch of water commonly called the Atlantic Ocean between here and there. ;-) ... No, not as a rule. This question has helped me pin
Message 17 of 23 , Nov 5, 2006
Ron Jeffries <ronjeffries@...> writes:

> I do like your version better, why weren't you here pairing with me?

There's a large stretch of water commonly called "the Atlantic Ocean" between
here and there. ;-)

> Would you, as a rule, have all your member variables invariant over
> the lifetime of your objects? I've seen people argue in favor of
> that, but state changes need to live somewhere, and on the call
> stack isn't always my favorite place.

No, not as a rule. This question has helped me pin down what I didn't like:
the mix of returning values and performing side effects. "score" should be a
pure function, returning the score, yet your version passes parameters to
itself for the recursive call by means of a side-effect: modifying the rolls
data member. I suspect that this is a characteristic of Temporary Field.

Incidentally, it bugs me that I missed the flaw. I was focusing on the
structure of the code and how it reflected the Haskell, but that's not really
an excuse; I've written code to score bowling enough times (though surely
fewer than your good self) that I should have seen it.

When I showed her your follow-up article, my wife chastised me for posting
untested code: "I thought you always wrote tests first!".

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• Hello, Anthony. On Sunday, November 5, 2006, at 7:20:26 PM, you ... Yes, it does pass the parms using a member variable, and that s certainly questionable. In
Message 18 of 23 , Nov 5, 2006
Hello, Anthony. On Sunday, November 5, 2006, at 7:20:26 PM, you
wrote:

>> Would you, as a rule, have all your member variables invariant over
>> the lifetime of your objects? I've seen people argue in favor of
>> that, but state changes need to live somewhere, and on the call
>> stack isn't always my favorite place.

> No, not as a rule. This question has helped me pin down what I didn't like:
> the mix of returning values and performing side effects. "score" should be a
> pure function, returning the score, yet your version passes parameters to
> itself for the recursive call by means of a side-effect: modifying the rolls
> data member. I suspect that this is a characteristic of Temporary Field.

Yes, it does pass the parms using a member variable, and that's
certainly questionable. In the latest article, just posted, I went
back to passing the parms all over the map. Every single method in
the class wants to look at the current rolls! I understand the
debate but it seems to me that when all the methods want the same
value, a member variable might be a decent approach.

> Incidentally, it bugs me that I missed the flaw. I was focusing on the
> structure of the code and how it reflected the Haskell, but that's not really
> an excuse; I've written code to score bowling enough times (though surely
> fewer than your good self) that I should have seen it.

Well, I have this unpopular theory that untangling recursions is
harder than untangling iterations. Dan Mead has communicated via
email that he has a version that passes a couple of zeros as end
markers, and that that fixes the bug. I find that I can't reason
effectively about whether that would work, or not.

Could be a personal problem, of course ...

> When I showed her your follow-up article, my wife chastised me for posting
> untested code: "I thought you always wrote tests first!".

Well, you had some excuse about not having a Java compiler with you
at the time ... ;->

Ron Jeffries
www.XProgramming.com
Fatalism is born of the fear of failure, for we all believe that we carry
success in our own hands, and we suspect that our hands are weak. -- Conrad
• ... I agree that it ought to be a member. I just happen to think that a final member of a method object is more appropriate in this case. YMMV. ... Just
Message 19 of 23 , Nov 5, 2006
Ron Jeffries <ronjeffries@...> writes:

> Hello, Anthony. On Sunday, November 5, 2006, at 7:20:26 PM, you
> wrote:
>
>>> Would you, as a rule, have all your member variables invariant over
>>> the lifetime of your objects? I've seen people argue in favor of
>>> that, but state changes need to live somewhere, and on the call
>>> stack isn't always my favorite place.
>
>> No, not as a rule. This question has helped me pin down what I didn't like:
>> the mix of returning values and performing side effects. "score" should be a
>> pure function, returning the score, yet your version passes parameters to
>> itself for the recursive call by means of a side-effect: modifying the rolls
>> data member. I suspect that this is a characteristic of Temporary Field.
>
> Yes, it does pass the parms using a member variable, and that's
> certainly questionable. In the latest article, just posted, I went
> back to passing the parms all over the map. Every single method in
> the class wants to look at the current rolls! I understand the
> debate but it seems to me that when all the methods want the same
> value, a member variable might be a decent approach.

I agree that it ought to be a member. I just happen to think that a "final"
member of a method object is more appropriate in this case. YMMV.

>> Incidentally, it bugs me that I missed the flaw. I was focusing on the
>> structure of the code and how it reflected the Haskell, but that's not really
>> an excuse; I've written code to score bowling enough times (though surely
>> fewer than your good self) that I should have seen it.
>
> Well, I have this unpopular theory that untangling recursions is
> harder than untangling iterations. Dan Mead has communicated via
> email that he has a version that passes a couple of zeros as end
> markers, and that that fixes the bug. I find that I can't reason
> effectively about whether that would work, or not.

Just adding an empty frame would certainly not work, as it would cause a
tenth-frame strike to have the bonus rolls scored as a new frame, since there
would now be 5 rolls left rather than 3. I thought for a second that you could
just have them always there, and zero if not used, this would cause
tenth-frame spares to be scored wrong, as there would be four rolls
remaining. Changing the termination to be 4 rolls left rather than 3 would
break games with both 9th and 10th frames being strikes.

Bowling is such that you cannot work out the frames going backwards, so you
need the framecount to know whether the 3 rolls left are 9th+10th, or
10th+bonus. The problem with the recursive solutions is not that their
recursive, but that they try and get away from that fact.

BTW, in your final version in "Recurring Drama", I think "remainingFrames" is
a better name than "frameNumber", since frame numbers tend to increase from 1
to 10, not decrease from 10 to 1.

Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
• Hello, Anthony. On Sunday, November 5, 2006, at 8:52:06 PM, you ... I share your intuition. Dan claims that it will work. So far I don t know whether it
Message 20 of 23 , Nov 5, 2006
Hello, Anthony. On Sunday, November 5, 2006, at 8:52:06 PM, you
wrote:

>> Well, I have this unpopular theory that untangling recursions is
>> harder than untangling iterations. Dan Mead has communicated via
>> email that he has a version that passes a couple of zeros as end
>> markers, and that that fixes the bug. I find that I can't reason
>> effectively about whether that would work, or not.

> Just adding an empty frame would certainly not work, as it would cause a
> tenth-frame strike to have the bonus rolls scored as a new frame, since there
> would now be 5 rolls left rather than 3. I thought for a second that you could
> just have them always there, and zero if not used, this would cause
> tenth-frame spares to be scored wrong, as there would be four rolls
> remaining. Changing the termination to be 4 rolls left rather than 3 would
> break games with both 9th and 10th frames being strikes.

I share your intuition. Dan claims that it will work. So far I don't
know whether it actually does run all the tests, and I certainly
don't see why it WOULD work. But I also don't know just what his
code is going to look like.

> Bowling is such that you cannot work out the frames going backwards, so you
> need the framecount to know whether the 3 rolls left are 9th+10th, or
> 10th+bonus. The problem with the recursive solutions is not that their
> recursive, but that they try and get away from that fact.

Interesting points!!

> BTW, in your final version in "Recurring Drama", I think "remainingFrames" is
> a better name than "frameNumber", since frame numbers tend to increase from 1
> to 10, not decrease from 10 to 1.

You're right.

Ron Jeffries
www.XProgramming.com
Baka ni tsukeru kusuri wa nai. -- Japanese Proverb
• ... programs. Isaac, you might not have read the programs Ron mentioned, but you certainly have read your own programs. This one
Message 21 of 23 , Nov 6, 2006
--- In extremeprogramming@yahoogroups.com, "igouy2" <igouy2@...> wrote:
>
> --- In extremeprogramming@yahoogroups.com, Ron Jeffries
> <ronjeffries@> wrote:
> > Isaac, I feel sure that had you noticed the fatal defect in Dan's
> > original Haskell, and the Ruby and Java programs based on it, you'd
> > have gleefully reported it here. Yet, with your 30 years of
> > experience in recursion, you did not. Recursive algorithms do not
> > give up their secrets easily.
>
> I'm afraid I haven't read his program or your program. I knew that
> you'd already seen the pattern-matching bowling game programs I wrote
> in Clean - so I chose to gleefully remind you of those working
programs.

Isaac, you might not have read the programs Ron mentioned, but you

is indeed working, because it uses a frame counter, but this one

isn't. It does have the defect...

In the newsgroup thread from January 2005, I didn't find any note
about the defect, so I assume you thought both programs would be working.

This supports Ron's point, doesn't it?

Regards,
Pit
• ... working. ... LOL! No it doesn t support Ron s point. (Assuming we understand Ron s point to be that this error has something to do with the solution
Message 22 of 23 , Nov 6, 2006
> Isaac, you might not have read the programs Ron mentioned, but you
>
>
> is indeed working, because it uses a frame counter, but this one
>
>
> isn't. It does have the defect...
>
> In the newsgroup thread from January 2005, I didn't find any note
> about the defect, so I assume you thought both programs would be
working.
>
> This supports Ron's point, doesn't it?
>
> Regards,
> Pit
>

LOL!

No it doesn't support Ron's point. (Assuming we understand "Ron's
point" to be that this error has something to do with the solution
being recursive rather than iterative.)

It just demonstrates that I'm capable of breaking something I wrote a
year earlier.

Questions for code archaeologists
- is the fact that the Nov 2003 (shown again in Jan 2005) program
works correctly just a happy accident that followed from the chance
use of framecount in a termination condition?
- is the fact that the Nov 2003 iterative program works correctly just
a happy accident that followed from the chance use of framecount in a
termination condition?
- was the problem understood in Nov 2003 and misunderstood in Jan 2005
when the second incorrect solution was created?
- was there ever a test case for this error? (If not we should suspect
that the problem hadn't been recognised.)

There are obvious lessons here and they run counter to Ron's statement
"I fancy I understand Bowling scoring rather well now, having
programmed it so many times."

The fact that we understood a problem well the last time we programmed
it doesn't mean that we are still mindful of the problem details in
the way we were then.
The fact that our program was correct the last time doesn't mean we
understood the problem then.
• ... -snip- ... I ve looked at the various Bowling Game programs I wrote back in 2003, and I ve looked through those old discussion group postings. 1) afaict I
Message 23 of 23 , Nov 8, 2006
--- In extremeprogramming@yahoogroups.com, "igouy2" <igouy2@...> wrote:

-snip-
> Questions for code archaeologists

I've looked at the various Bowling Game programs I wrote back in 2003,
and I've looked through those old discussion group postings.

1) afaict I never used these explicit test cases to check any of the
bowling game programs I wrote
[0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 10, 2,3]
[0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 10, 2,3]

2) Back in 2003 I did seem to understand that "To calculate the total
score for a game, we need to know if we've reached the tenth frame."