Well a lot has been going on, but when I reflected upon an assembly someone handed me today I saw something that got my writing juices flowing again.
(Plus I totally have to take a break from Skyrim :))
When you open someone else's code you never now what you're going to find. Is it going to be that Christmas present you've oh so been waiting for or the dreaded pair of white socks....
Today I got the socks.
Enough with the metaphors *turns on a skrillex live set* let's get technical.
What I found was the GOTO keyword I was taught long ago learning Assembler but was quickly told to forget again once I started C and at the latest C++ and C# once the object orientation started.
Now I've done some reading on the subject and discovered the GOTO actually has defenders and one actually has to pick sides in the discussion (which has me pretty surprised because I thought this subject is a "no brainer").
Before I get going: I'm on the no GOTO side of this debate (from here on known as the Light Side).
I'm going to try my best on picking an example which is easy but at the same time not too trivial.
Starting off with GOTOs |
Program:
- So we start of randomly picking a number between 0 and 2
- Depending on the index we alter the string and jump to one of our labels
- CorrectOutputThenLaunchSubroutine alters the string again (because we <3 DnB right?)
- ExecuteSubroutine display the string on the screen and we're go to go (pun not intended)
First of all: NO Intellisense for labels...need I even continue? I don't know about you but I've pretty much reached the point where I let the IDE generate as much code as possible for me. So now I'm going to start memorizing label names which are supposed to make my life easier....sorry but not me :)
Next up which you Assembler programmers all remember is: The order of labels are crucial, order them wrong and you're going to have code executing in all kinds of directions.
Finally in terms of scalability, keeping track of a small number of your own labels isn't going to be the hardest task in the world, but imaging that small number growing and growing and having that code handed to you from a colleague developer...get your machete and start exploring.
OK enough GOTO bashing. I mean in low-level programming it is pretty much the only way to go. But it shouldn't be the way to go in high-level programming. Especially when there are so many alternatives to choose from which can make your own life easier and that of your colleagues.
To keep my syntax as DRY (don't repeat yourself) as I can get it and because my software engineering lecturer taught me a strong dislike of the switch/case, I like to use the following approach:
- Dictionaries
- Delegates
- Lambda Expressions
The first step is to package what we did in the case blocks into a pseudo function signature which we can use as a delegate. Because in each block we're basically taking a string, changing it and returning it we can define the following delegate:
The myStringDelegate |
Remember function pointers from C++? *wink wink* I knew you did.
For everybody else, this is "merely" a data type which we can later give a function signature (or a lambda expression) and Invoke that function whenever we want.
The next step is to assign the numbers we used in the first example for the cases in our switch block to the delegates we are going to create. This can be done by declaring and filling a Dictionary with int as the index and myStringDelegate as the value type as such:
The Dictionary which maps an int to the corresponding subroutine / lambda expression |
The dictionary is awaiting a myStringDelegate which receives and returns a string. The lambda syntax goes like this:
(/*parameters here*/) => {/*operations here*/}
So basically the functionality of the entire program can be extended upon by adding another entry to the dictionary and changing the max value of the number generator to the length of the list. And I personally find it very easy to read (once you've gotten the hang of those lambdas :)).
During the run time of the program, after a number has been chosen using random, the corresponding code block can be invoked by one single line of code:
Method invocation via the subroutineDictionary |
The dictionary functionality can also be used to store different data types to alter the flow of a program. Remember those mean things the program had to say about DnB and how we got rid of them? If you declare and fill a second Dictionary the same numbers can be linked to boolean expressions to determine if a string should be replaced during runtime:
The dictionary which determines if a string should be replaced |
Replace condition |
Before I recap here's the whole thing remodeled which semantically produces the same results but is (in my opinion) much more readable and can easily be extended upon if the requirements arise:
Version 2.0 without those pesky GOTOs |
Think of your fellow programmers when you write code, at least have the intention to produce highly readable, understandable and extendable code. Because it could be you one day on the other side, machete in hand, trying to figure out the the mazes other people have built and hoping to make it back out alive.
I leave you with Randall Munroe's (www.xkcd.com) thoughts on this matter:
http://xkcd.com/292/ |
I'm off to Skyrim...still haven't reached level 50 :) shame on me.