Genetic Algorithms allow for a rapid exploration of a problem domain. This exploration is automated and intentionally random. What happens if you are exploring a problem domain programmatically? You want to allow yourself room to explore this problem domain with the greatest efficiency.
To explore this, let’s start with a simple case: converting a string to the upper case representation of that string.
Results of Low-Tech ToUpper Function
If you think about this while looking at an ASCII table, you may very well notice that all lower case characters are sequential and have ASCII codes between 97 and 122. Concomitantly, all upper case characters are sequential and have ASCII codes between 65 and 90. It doesn’t require much mathematical acumen to determine that you can check the ASCII value, and if it is between 97 and 122, subtract 32. The more mathematically astute will notice that 32 is a power of two, and thus the computation could be computed using a logical and. Thus, we could create a solution that uses very few assembly language instructions. A very simple implementation would be:
mov ecx, LENGTHOF array
mov esi, OFFSET array
and BYTE PTR [esi], 11011111b
Obviously, it’s not terribly likely that anyone today would be implementing much using assembly language, but this solution maps easily into higher level languages. If you take a look at how this is done in C, you can find the following macros (which uses the subtraction method rather than the logical and method) in ctype.h:
#define __ascii_toupper(c) ( (((c) >= 'a') && ((c) <= 'z')) ? ((c) - 'a' + 'A') : (c) )
#define _toupper(_Char) ( (_Char)-'a'+'A' )
So, it seems that we have the problem solved, and we can simply call a macro or a function to have our text converted to uppercase.
This solution only really works on English text. What if I am localizing to Greek? A lower case alpha is unicode character number 945, while an upper case alpha is 913. Oops. Now, I am not converting this character to its upper case equivalent. The characters are still 32 bits apart, so I could still use a similar technique, but now I have to add a series of ranges - I can't just use 97 to 122. How do I figure that out? Perhaps I remember the upper and lower case Greek letters from math class, but what about other alphabets? Can I be certain that I am correctly implementing it for every language that Unicode supports?
A good approach is to abstract away the problem, and implement what you know you are supporting. If you don't yet have a version of your application localized to Cyrillic, then you don't necessarily have to implement this method for that today, but you would like to be able to implement the ToUpper function once you have localized the rest of the application without having to scour your code ripping and replacing to add this functionality in.
The .NET Framework implements the ToUpper function very much like this. The ToUpper method of System.String passes the call to the CultureInfo object (which will either be the current culture or the culture you specify). If you add support for additional locales, you can just add additional CultureInfo objects, without modifying the code that already exists. This allows localization to evolve naturally without touching the rest of the code.
One real world example that I worked with recently was with the notion of authentication and authorization. I have seen many applications where authentication logic was hard wired into the web page. The same is true of authorization. This makes it difficult to change authentication and authorization if (or, more likely, when) you get to a level of complexity where identity management becomes a key initiative. If you bake in authentication throughout your database, then what happens if you begin using a dedicated, global authentication store, such as Active Directory or ADAM? If you hard code in authorization, then what happens if you move to a dedicated, global authorization store, such as Windows Authorization Manager? If you bake all of this functionality into your web pages, then what happens when you want to begin exposing some of that functionality through web services? This is one area where things are likely to evolve - therefore, it makes sense to architect your solution to support this natural evolution, rather than having the evolution cause you more work later on.