Loading ...
Sorry, an error occurred while loading the content.

New Article: Haskell Bowling

Expand Messages
  • Ron Jeffries
    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
    • 0 Attachment
      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, TDD style,
      in Haskell. It was fun and interesting. Here I present some
      discussion, his program, and a Java program in a similar style.

      http://www.xprogramming.com/xpmag/dbcHaskellBowling.htm

      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
    • Anthony Williams
      ... 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
      • 0 Attachment
        Ron Jeffries <ronjeffries@...> writes:

        > 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, TDD style,
        > in Haskell. It was fun and interesting. Here I present some
        > discussion, his program, and a Java program in a similar style.
        >
        > http://www.xprogramming.com/xpmag/dbcHaskellBowling.htm

        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
      • Ron Jeffries
        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
        • 0 Attachment
          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.
        • Anthony Williams
          ... 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
          • 0 Attachment
            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
          • Ron Jeffries
            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
            • 0 Attachment
              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.
            • Ron Jeffries
              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
              • 0 Attachment
                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.

                I was chatting with Chet today about this, while we sat in the
                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.
              • Anthony Williams
                ... 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
                • 0 Attachment
                  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
                • Anthony Williams
                  ... 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
                  • 0 Attachment
                    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;
                    return total;
                    }

                    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;
                    return total;
                    }

                    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;
                    return total;
                    }

                    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
                  • Anthony Williams
                    ... 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
                    • 0 Attachment
                      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.

                      .subList isn't too bad.

                      Thanks for the discussion,

                      Anthony
                      --
                      Anthony Williams
                      Software Developer
                      Just Software Solutions Ltd
                      http://www.justsoftwaresolutions.co.uk
                    • Ron Jeffries
                      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
                      • 0 Attachment
                        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.
                      • Ron Jeffries
                        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
                        • 0 Attachment
                          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.
                        • Anthony Williams
                          ... 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
                          • 0 Attachment
                            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
                          • Ron Jeffries
                            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
                            • 0 Attachment
                              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.

                              > .subList isn't too bad.

                              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
                              learn about.

                              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
                            • igouy2
                              ... 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
                              • 0 Attachment
                                --- In extremeprogramming@yahoogroups.com, Ron Jeffries
                                <ronjeffries@...> wrote:
                                >
                                > 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, TDD style,
                                > in Haskell. It was fun and interesting. Here I present some
                                > discussion, his program, and a Java program in a similar style.
                                >
                                > http://www.xprogramming.com/xpmag/dbcHaskellBowling.htm

                                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 :-)

                                http://groups.google.com/group/comp.object/msg/b8dfcb9fcaa45b4e

                                http://groups.google.com/group/comp.object/msg/f37aea0bf095cc72


                                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."
                              • Ron Jeffries
                                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
                                • 0 Attachment
                                  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
                                  To follow the path:
                                  Look to the master; Follow the master; Walk with the master;
                                  See through the master; Become the master. -- Modern Zen Poem
                                • igouy2
                                  ... 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
                                  • 0 Attachment
                                    --- 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.
                                  • Anthony Williams
                                    ... 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
                                    • 0 Attachment
                                      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
                                    • Ron Jeffries
                                      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
                                      • 0 Attachment
                                        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
                                      • Anthony Williams
                                        ... 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
                                        • 0 Attachment
                                          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
                                        • Ron Jeffries
                                          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
                                          • 0 Attachment
                                            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
                                          • Pit Capitain
                                            ... 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
                                            • 0 Attachment
                                              --- 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
                                              certainly have read your own programs. This one

                                              http://groups.google.com/group/comp.object/msg/b8dfcb9fcaa45b4e

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

                                              http://groups.google.com/group/comp.object/msg/f37aea0bf095cc72

                                              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
                                            • igouy2
                                              ... 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
                                              • 0 Attachment
                                                > Isaac, you might not have read the programs Ron mentioned, but you
                                                > certainly have read your own programs. This one
                                                >
                                                > http://groups.google.com/group/comp.object/msg/b8dfcb9fcaa45b4e
                                                >
                                                > is indeed working, because it uses a frame counter, but this one
                                                >
                                                > http://groups.google.com/group/comp.object/msg/f37aea0bf095cc72
                                                >
                                                > 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.
                                                http://groups.google.com/group/comp.object/msg/45ed159928b69648


                                                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.
                                              • igouy2
                                                ... -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
                                                • 0 Attachment
                                                  --- 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."

                                                  http://groups.google.com/group/comp.object/msg/d365e30e4e1e56de

                                                  However it's not obvious that I understood all the ways that programs
                                                  might fail if they didn't distinguish between the tenth and previous
                                                  frames - which leaves a question mark over how well I understood the
                                                  problem ;-)


                                                  3) It seems safe to say that the understanding was implicit, and
                                                  not remembered a year later - in a way that would not have been likely
                                                  if we had those explicit test cases.
                                                Your message has been successfully submitted and would be delivered to recipients shortly.