Python vs Go Cage Match! Fight!

March 3, 2010, 8:30 am

So this is not exactly a comparison between Python and Go. I just wanted to use my Gopher eating a Python logo image.

I love Python, it is sleeping in on Saturday mornings, my favorite book being picked up by HBO, baby holding onto pinky finger ... well, you get the idea, I like it a lot. I use it extensively for the piles and piles of code I write that never sees the light of day. Code that pre-processes files, scrapes web sites, munges together data sets, but doesn't actually end up anywhere near a user. When I saw Rob Pike talk about Go at a Sydney GTUG meeting, it occurred to me that a slick, modern, compiled language might be worth looking at for some of these behind the scenes projects that I embark upon.

Compiled vs Interpreted

Ok, duh! This is why I am here. I love Python with the heat of a thousand suns, but waiting a couple of hours for a process to finish, cools my adour a little. Compiled languages are fast and, from what I have seen, Go is a fast compiled language that also compiles fast. Fast is a feature. I have stuff to finish so I can go and watch The Sopranos.

Strong vs loose types

Occasionally, when I find myself in a particularly self deprecating frame of mind, I feel like I fit the mold of a duct tape programmer a little too much. Not in Joel Spolsky's generous, smart and get things done kind of way, but in the dumb and makes lots of mistakes kind of way. For me programming in a loosely typed language (like Python or PHP) tends to be a sequence of tiny, and sometimes humiliating, steps from a hideously broken thing to something approximating a working system. It would be nice if I could build something that was a little less flawed from the beginning. My experience is that a strongly typed language helps me do that:

// ahh ... compile error :P var testStringMap = map[string] int {8:"eight"}

Useful built-in types

When I am forced to work in languages (and to be fair, this doesn't happen very often any more) that don't have strings, maps, arrays just built-in, it causes me physical pain:

STL I used to like you because it beat writing this stuff myself but, you kinda suck.

typedef std::map StringIntegerMap; StringIntegerMap mapThatMakesMeTypeTooMuch; int theNumberEight = 8; std::string alsoTheNumberEight ("Eight"); mapThatMakesMeTypeTooMuch.insert(StringIntegerMap::value_type(theNumberEight, alsoTheNumberEight)); StringIntegerMap::const_iterator it; it = mapThatMakesMeTypeTooMuch.find (theNumberEight); if (it != mapThatMakesMeTypeTooMuch.end ()) std::string whatWasThatNumberAgain = it->second;

Python .. is awesome.

pythonDictionaryFTW = {8 : "Eight"} theNumberEight = 8 if (theNumberEight in pythonDictionaryFTW): whatWasThatNumberAgain = pythonDictionaryFTW[theNumberEight]

The map semantics in Go are just a little weird. I am sure I will get used to it. I got used to STL after all.

var testIntStringMap = map[int] string {8:"eight"} var theNumberEight int = 8 if mappedString, ok := testIntStringMap[theNumberEight]; ok { fmt.Printf ("Mapped String %s\n", mappedString) }

Libraries

There are smarter, better looking programmers out there who can build awesome stuff that I want to use. I think the biggest reason not to switch from Python to Go is the range of third party libraries available for Python. Obviously this is something that will get resolved over time and I am sure there are lots of clever Google people squirreling away in their 20% time to build me awesome stuff (me personally). Beautiful Soup port for Go anyone?

Conclusions

I have lots more to learn about Go, but at this point I like it. It has a weird edgy feel about it that makes me feel a little smarter than I actually am, but it also reminds me a lot of Python and I luurve Python. I am hoping that I can find the time to actually build something real in the language and acquire enough knowledge to crush all resistance in the Go StackOverflow tag.

Permalink - Comments - Tags: Development,Google

Subscripts and Superscripts in a UITableView

February 28, 2010, 11:47 pm

I have written a handful of iPhone apps now and used UITableView extensively in one of them. Until recently, I had never needed to put any rich text into a UITableViewCell.

The data I am using for this project is basically an index list of mini HTML documents, with an index term for each document. I use the UITableView to render the index. Most of the index terms are in plain text, but there are handful of them that include HTML tags to indicate sub-scripted or super-scripted characters:

Glucose (C6H12O6)

My initial reaction to cases like this was to create a UITableViewCell that had a UIWebView as a subview. I could just stick my HTML in the sub view and voila! my index would be rendered perfectly:

// get the term so we can check what is in it NSMutableString * term = [[[NSMutableString alloc] initWithFormat:@"%@", [dataController objectInListAtIndex:[termIndex intValue]].term] autorelease]; // need to work out what sort of cell this needs to be NSRange textRange =[term rangeOfString:@"<"]; bool foundHtml = NO; if(textRange.location != NSNotFound) foundHtml = YES; NSString * cellIdentifier = [[[NSString alloc] initWithFormat:@"%@", (foundHtml ? @"HtmlCell" : @"Cell") ] autorelease]; // Dequeue or create cell of the appropriate type. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { // didn't find a reusable cell, create one based on the type if (foundHtml) { // Grab the UITableViewCell from the HtmlCell XIB NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"HtmlCell" owner:self options:nil]; cell = [topLevelObjects objectAtIndex:0]; } else { // This cell doesn't have any markup, just use a regular cell cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease]; cell.textLabel.textColor = [UIColor blackColor]; cell.textLabel.highlightedTextColor = [UIColor whiteColor]; } cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } // set the text if (foundHtml) { // grab the htmlView from the cell and set it's content HtmlCell * htmlCell = (HtmlCell*) cell; [htmlCell.htmlView loadHTMLString:[NSString stringWithFormat:@"%@", term] baseURL:nil]; } else { // set the cell text normally cell.textLabel.text = term; } return cell;

I had a nagging feeling about approaching the problem this way and after the writing the code and seeing the woeful performance of UIWebView I remembered what it was. Months ago I listened to this mobile orchard interview with the Joe Hewitt, creator of the Facebook iPhone app and the open source Three20 Project. Seeing the slugglish rendering of my beautifully marked up index terms, I recalled that the unsuitability of UITableView for web content, was one of the motivations for the Three20 project (or it's original implementation in the Facebook app).

I decided against using Three20 partially because of an unreasonable case of not invented here syndrome, but also because I didn't have the time to invest in learning a new framework. I also felt like my problem was a pretty simple subset of the rich text rendering problem (just the sub-scripts and super-scripts), so there must be a simple solution.

It occurred to me that UITableView does a great job of rendering unicode characters (both Ballet Index and Karate Index render unicode characters in the table and they look great). So maybe there are sup-scripted and super-scripted unicode characters for the small set of characters that I needed (+,- and the numbers)?

Yep, there is! All I needed to do was recurse my way through each of the HTML elements in my index and replace them with the appropriate unicode character. Problem solved:

- (unichar) mapCharacter:(char)sourceChar forElement:(NSString*)element { if ([element localizedCaseInsensitiveCompare:@"sup"] == NSOrderedSame) { if (sourceChar == '2') return 0xB2; if (sourceChar == '3') return 0xB3; if (sourceChar >= '0' && sourceChar <= '9') return (0x2070 + (sourceChar - '0')); if (sourceChar == '+') return 0x207A; if (sourceChar == '-') return 0x207B; if (sourceChar == -82) return 0x00AE; } if ([element localizedCaseInsensitiveCompare:@"sub"] == NSOrderedSame) { if (sourceChar >= '0' && sourceChar <= '9') return (0x2080 + (sourceChar - '0')); if (sourceChar == '+') return 0x208A; if (sourceChar == '-') return 0x208B; if (sourceChar == -82) return 0x00AE; } return sourceChar; } // N.B. This code works for a very specific set of data. It doesn't handle // nested html tags for instance. - (NSMutableString*) processMarkupCell:(NSMutableString*) cellText { NSRange openRange =[cellText rangeOfString:@"<"]; if (openRange.location == NSNotFound) return cellText; // found an angle bracket ... need to remove the elements and map the sub/sup characters NSRange closeRange =[cellText rangeOfString:@">"]; NSRange elementRange = openRange; elementRange.location++; elementRange.length = closeRange.location - elementRange.location; // we get the element so we can use the appropriate mapping for each character (sup or sub) NSString * element = [[[NSString alloc] initWithFormat:@"%@", [cellText substringWithRange:elementRange]] autorelease]; // set up the new cell text NSRange prefixRange; prefixRange.location = 0; prefixRange.length = openRange.location; // stick everything before the element in the newCellText NSMutableString * newCellText = [[[NSMutableString alloc] initWithFormat:@"%@", [cellText substringWithRange:prefixRange]] autorelease]; // find out where we need to stop NSRange stopRange; stopRange.location = closeRange.location + 1; stopRange.length = [cellText length] - (closeRange.location + 1) ; NSRange nextOpenRange = [cellText rangeOfString:@"<" options:(NSStringCompareOptions)0 range:stopRange]; NSRange nextCloseRange = [cellText rangeOfString:@">" options:(NSStringCompareOptions)0 range:stopRange]; NSRange postfixRange; postfixRange.location = nextCloseRange.location + 1; postfixRange.length = [cellText length] - (nextCloseRange.location + 1); // start mapping the first character after the closed element for (int currentPosition = closeRange.location + 1; currentPosition < nextOpenRange.location; currentPosition++) { // append each mapped character in the newCellText [newCellText appendFormat:@"%C", [self mapCharacter:[cellText characterAtIndex:(NSUInteger)currentPosition] forElement:element]]; } // stick everything after the closing element in newCellText (other tags will be resolved recursively) [newCellText appendFormat:[cellText substringWithRange:postfixRange]]; // recurse through the string .. getting all the elements return [self processMarkupCell:newCellText]; }

Permalink - Comments - Tags: Development,iPhone

No cmp argument to list.sort () in Python 3.0

February 23, 2010, 10:07 pm

One of the changes introduced in Python 3.0 was the removal of the cmp argument from list.sort () and builtin.sorted (). This is all part of Python 3.0's intentionally backwards incompatible feature set, something I whole heartedly agree with (for reasons that will become clear).

I had been blissfully unaware of the performance implications of using the cmp argument (mostly because performance is rarely a consideration for the tools I write in Python) and had code like this sprinkled generously around the place:

# sort an array by the length of it's constituents l.sort(cmp=lambda x, y: len(x) - len(y))

I hadn't read the whole Python 2.4 article on sorting, which explains how cool the key argument is and how calling your key parameter once for each member in the list is much more efficient. So when I went to use the cmp argument in Python 3.0 it cheerfully failed and sent me off to the What�s New In Python 3.0 page at python.org for an explanation.

This is exactly the problem that Python 3.0 is trying to fix, unfortunately the explanation on the What's New page was sadly lacking:

builtin.sorted() and list.sort() no longer accept the cmp argument providing a comparison function. Use the key argument instead.

What I needed in addition, to this terse repetition of the error message I got from the interpreter, was something like:

The value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes.

This all seems fairly trivial in retrospect but I spent real time hunting around for a description of this fangled key thing and built up enough angst to write this admittedly petulant post.

I doubt very much that a like minded, slightly befuddled individual will find his way here, so mostly for my own reference, sorting by string length:

def cmpLen (other): return -1 * len(other) # sort by string length (descending) l.sort (key=cmpLen)

Permalink - Comments - Tags: Development

Small things amuse ...

February 9, 2010, 4:25 pm

Recursion is fun. Just sayin...

mappings = { 'o':['1','2'], 'k':['d','l','w'] } def printVariants (substring): print (substring) for i in range(0, len(substring)): if mappings.has_key (substring[i]): for mapped in mappings[substring[i]]: newSubstring = substring[:i] + mapped + substring[i + 1:] printVariants (newSubstring) printVariants ("fook")

Permalink - Comments - Tags: Development

Google Maps Sandbox

February 5, 2010, 10:48 pm

I have been a Google Maps enthusiast for some time and of late have been venting some of that enthusiasm in the google-maps tag on Stack Overflow. Despite having answered a bucket load of questions and done quite a bit of development with the Google Maps API, I sometimes encounter a question whose solution requires some empirical testing.

To facilitate these tests I set up a sandbox page on my site to host my cobbled together examples. The process has been quite rewarding and I have found myself delving into areas of the API which I would have ignored for my own projects. Here are a few of my favorites:

  • Draw a square at an arbitrary point - This mostly involved taking someone else's awesome server side code, to determine a location an arbitrary distance/direction from a known point, and porting it to Javascript. Although I didn't get any questioner love on this one, the solution was still quite satisfying.
  • Directions - Before this question I hadn't had a chance to play with the GDirections functionality in the API. This simple example just grabs the route between two points. The corresponding questioner was having some trouble getting this to work and it turned out the problem was unrelated.
  • Travel time data - You can use the GDirections object without providing a map and directions div and just get the data back as a JSON response. In this demo I grabbed the driving time for the directions calculated between two points.
  • Overlays - Had a lot of fun answering this question with a simple demo for using GTileLayerOverlay. The ability to leverage to the Google Maps API with your own tilesets is very powerful.
  • Open street map tiles in Google maps - I implemented this demo for a question I didn't actually answer myself. I was browsing questions and found one that described how you can use the Google Maps API with an entirely separate map tile set, in this case from OpenStreetMap.org. This seemed like such a cool concept, I had to try it out.

Permalink - Comments - Tags: Development,Google