Let’s create a calculator with C# (Part 3)

Let’s create a calculator with C# (Part 3)

No Comments on Let’s create a calculator with C# (Part 3)

Quick summary of Part 2:

  • Focused on addressing problem areas of post 1 by researching and applying basic design concepts (i.e. user stories)
  • Wrote user stories for every button on the calculator to help me think through behavior of the calculator, which was very successful for getting me past the roadblocks in post 1
  • Reused some of my console calculator code from part 1, and added new code to handle UI input mainly for extracting numbers and operators from a string and then using those values to do math stuffs
  • Eventually produced a “working” calculator as per my goal in post 1, but also ran in to some design issues that resulted in over complicated code and tricky bugs

Accomplishments in this post:

  • Refactored and simplified code = improved calculator design and behavior
  • Number pad input feature
  • Speech synthesis feature
  • Voice recognition feature
  • GitHub and version control (see all my code for this post here)
  • TODO, BUG, HACK, and UNDONE comments

My original goal for this post was to apply some quick fixes to the known bugs and add a cool feature to wrap up the project. While I did intend to go that route, investigating the bugs and attempting to write quick fixes was painful…every time I would fix an existing bug, one or more would pop up, or break some of my existing code. Out of frustration and unwillingness to accept the obvious, I spent a decent amount of time trying to force things to work…as it turns out, you cannot hammer a square peg into a triangle hole.

The biggest time sink for me was trying to fix bugs that were a result of more than one operator in the string passed for calculation, such as something like “-5 – 10.” This example would break the calculation function because it only accepts one operator value, and the operator value would be determined through logic that followed these rough steps: 1) find the index of the operator character, 2) store the operator via index and substring, 3) store operand1 as anything before the index of the operator, and 4) store operand2 as anything after the index+1 substring range:

selectedOperator = equation.Substring(equation.IndexOf("*"), 1);
number1 = Convert.ToDouble(equation.Substring(0, equation.IndexOf("*"))); //stores all numbers before operator
number2 = Convert.ToDouble(equation.Substring(equation.IndexOf("*") + 1, equation.Length - (equation.IndexOf("*") + 1)));  //stores all numbers after operator
performArithmeticOperation(selectedOperator, number1, number2);

Considering the “-5 – 10” example, you’ll realize that step #3 would break because there’s nothing before the index of the first minus sign, and step #4 would break because it would try storing “5 – 10” in a double, which obviously would fail since there is a character in that string.  This problem further complicates as seen by other examples, such as “75*2-3” and several other edge cases.  I wasted a lot of time trying to apply quick fixes to this, which can be seen in a couple of reverted commits in my GitHub history.  One of the “fixes” that I spent a couple of days working on was an algorithm that finds all operators in a string, their index locations, all numbers between the found operators, and then a mess of if statements that could handle every type of combination of operator and math equation.  Long story short, it was very challenging and ultimately lead me to the decision to keep things simple and refactor the entire project.  However, it was still a good challenge, and I learned a lot from it…mainly, don’t use the contents of a string to store certain variables (see lesson #4 below for more on this).  I believe the approach I used to decompose a complex string and reconstruct it as a math equation will come in handy for later projects.


This GIF took me way too long to make

Four key lessons since the last post are:

  1. Using other people’s work to influence your own is good.  The open-source movement and community is so wonderful for aspiring programmers.  There are countless tutorials and examples that can easily be found through your preferred search engine.  Here are the people who helped me (thank you!):
  2. Taking extended breaks on programming projects are both good and bad, but probably better than bad. It’s been a little over 4 months since my last post on this project. I spent almost no time working on the calculator project until recently, and in retrospect was a good thing because it allowed me to approach the project, and programming in general, with a set of new eyes and openness to new ideas. It took me a two weeks of casual code review to become familiar with what I wrote in post 1 and 2, and during this time I found myself thinking “wtf?” fairly frequently and questioning why I chose certain design approaches. Ultimately, I ended up rewriting almost all of the code and using a much different and better design. I suppose on a larger, more complicated, project an extended break could actually do more harm than good because of the complexities involved.
  3. (GitHub) Version control is remarkably helpful and fun.  During my downtime I did start reading more about version control and GitHub, and it became immediately clear that there aren’t many reasons for developers to not use some type of version control.  GitHub is popular, and it’s fun having your own page where you can share your code for forking and see misc. stats on code changes.  I really enjoy how easy it is to drill down into file commits and clearly see what code was changed.  I also like how switching between branches on the windows client automatically updates my visual studio working project.  I’ve learned that committing often is better than doing lots of work and committing less frequently, since you could screw things up or want to revert for whatever reason with an easier method besides ctrl+z.  You can have further protection by never using the main branch for development…I use a “feature” or “working copy” branch and only use main for merging new features or bug fixes.  While there’s a handful of other cool things I like about GitHub (pull request discussions and collaboration opportunities, issue tracker, forking, merging, etc.), I still don’t fully understand it’s potential and best practices, and often find myself not understanding certain behavior between the client and web version.  Nevertheless, I look forward to using GitHub for my project and this blog so I can better document and share my code.
  4. Over complicating code is a sign your design is bad.  In my case, over complication of code was a result of using strings for things that I shouldn’t have.  Strings are hard to work with and shouldn’t be used as a source of data input/manipulation unless absolutely necessary.  My design in post 2 used textbox strings for everything and that was the sole reason for the confusing code and bugs I encountered.  It took me a long time to realize that I should set variables “behind the scenes” on button clicks instead of extracting those values directly from a users input, which hurt my pride a little bit.  For example, with the understanding that all we want to do is set an operator based on the user’s input, the below code should immediately be questionable given the overly complicated comments and code.
            if (equation.Contains("*"))
                /* - This block of commented code helped me think through how to write the uncommented code
                int lazyEquationIndex = equation.IndexOf("*");
                int lazyEquationLength = equation.Length;
                int lazyLength = equation.Length - equation.IndexOf("*");
                int lazyIndexPlusOne = equation.IndexOf("*") + 1;
                string lazyTest = "6*6";
                string lazyResult1 = lazyTest.Substring(0, lazyEquationIndex);
                string lazyResult2 = lazyTest.Substring(lazyIndexPlusOne, lazyEquationLength - lazyIndexPlusOne);
                 * */

                selectedOperator = equation.Substring(equation.IndexOf("*"), 1);
                number1 = Convert.ToDouble(equation.Substring(0, equation.IndexOf("*"))); //stores all numbers before operator
                number2 = Convert.ToDouble(equation.Substring(equation.IndexOf("*") + 1, equation.Length - (equation.IndexOf("*") + 1)));  //stores all numbers after operator
                performArithmeticOperation(selectedOperator, number1, number2);

That’ll do.

All things considered, I’m very happy with how this project is shaping up.  Considering it started off nearly as a failure, rebounded into a somewhat working calculator, and now transformed into a stable, simple calculator that can synthesize text-to-speech and recognize voice input…I feel damn good about my efforts.  It’s definitely not perfect, and a seasoned programmer surely would pick apart much of it, but overall it can do exactly what I want it to do and will serve as a stepping stone to other fun projects.  I like to imagine that some talented developer read through my first post, mocking my poorly planned and executed project, move on to my second post, still doubtful but hopeful for my potential, and finally to this post where he/she commends me with a pat on the head and a simple “That’ll do…that’ll do.”

There is a really good discussion on /r/learnprogramming about why programming is so damn hard, along with a very well written blog post by Erik Trautman @ Viking Code School, and I encourage anyone with an interest in programming to read it once, then again, and every time you feel lost or in despair during your programming journey.

Future exploration areas to consider for this project:

  • Custom UI
  • Google/Bing voice api for improved voice recognition
  • Copy/paste feature
  • History feature
  • Object oriented design
  • Test cases

Please visit my Calculator repository on GitHub to view/fork this project code.  Until I merge the feature branch with main, all of the code written as part of this post will be available in the feature branch.

About the author:


Leave a Reply

Back to Top