Peter Harkins's blog

Strings are a Domain-Specific Language

Question: Isn't a domain-specific language just the same thing as a library? (Source: Pretty much everyone the first time they hear of DSLs.)

Answer: No, a DSL is much more than a library, and I have an example that won't make you say, "Well, sure, if you're doing something that esoteric..."

NDAs: Fear and Shame

The two fundamental reasons NDAs exist are fear and shame, and that's only halfway a bad thing.

You want a little healthy fear in your life, it keeps you from trying to pet those cute little bear cubs. In business, it keeps you paying attention to things like what the competition is up to, to if your burn rate is sustainable, and how important those last few bugs are.

Most NDAs exist because of two different and worthwhile fears: early competition and secret sauce. If you and two buddies have read Getting Real and struck out on your own to start a web-based business, you'd like to delay the day that knockoffs start appearing. Alternatively, if you're Google, you have hordes of resourceful competitors and abusers who'd love to mine the offhand comments of your engineers.

But the nearly-as-common motivator behind NDAs is shame. You could call it fear of being found incompetent, but the word for that is shame. A shame-powered NDA will invariably be described as an important security measure, but the business is covering up that it runs everything in a slipshod, last-minute, "this is good for now and we need it" manner. Most organizations just barely work and spend their time lurching between crises, which is mildly disconcerting in an interdependent society but handy for breaking the spirit of idealistic young college graduates.

Lambda at Work

Finally, several years after learning lambda expressions, I got a chance to use one at work a few days ago. As long as I'm putting a notch in my nerd belt, I'd like to write about what lambda is and how it can be useful.

A lambda expression defines an anonymous function. Here's a regular function definition:

def inc(x):
    return x + 1

This definition binds the name inc in the local namespace to a function object. To get the exact same functionality using lambda, assign the lambda expression to a variable:

inc = lambda x: x + 1

A lambda has two parts: the argument list (only one arg in this case) before the: and an expression after. It can't contain statements (like assignments or print) because it's an expression itself. This is a pretty useless example, so let me show how I used it today.

Python Flyweights

I mentioned at the end of my post on Python Equality that another way to solve the example given was to use the flyweight pattern. I gave code for playing cards that would end up with many small duplicate objects in memory, and that memory usage can be reduced if (as in the example) the objects don't have extra state that wasn't used for testing equality.

Let's look at the final version of the Card class and its usage again:

values = ('2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A')
suits = ('h', 'c', 'd', 's')
class Card:
    def __init__(self, value, suit):
        self.value, self.suit = value, suit

    def __repr__(self):
        return "<Card: %s%s>" % (self.value, self.card)

    def __eq__(self, card):
        return self.value == card.value and self.suit == card.suit

    def __ne__(self, card):
       return not self.__eq__(card)

>>> c1 = Card('J', 'h')
>>> c2 = Card('J', 'h')
>>> c1 == c2
>>> id(c1), id(c2)
(-1210559028, -1210558804)

As designed in the previous blog post, two different objects (as seen by their different ids) equate because of the custom __eq__() handler.

But this is a bit silly -- Cards are so small and simple, having identical objects is wasteful. If we're writing the code for a casino, we don't really want several thousand Jacks of Hearts, we want many references to one object. The idea is that instantiating a Card object checks a hidden pool of objects for a duplicate and returns it, creating a new object only if needed. (Code based on that of Duncan Booth.)

import weakref

class Card(object):
    _CardPool = weakref.WeakValueDictionary()

    def __new__(cls, value, suit):
        obj = Card._CardPool.get(value + suit, None)
        if not obj:
            obj = object.__new__(cls)
            Card._CardPool[value + suit] = obj
            obj.value, obj.suit = value, suit

        return obj

Notice that this uses new-style classes. (Side note: I cringe at anything named "new", "next", "updated", etc. because they tell me nothing. If the only thing you can say about a reimplementation is that it's not the old one, put down your copy of Refactoring and back away from the computer. Take up writing toothpaste advertisements.) If you're wondering what's up with __new__, Guido explains the difference best:

__new__ is the first step in instance construction, invoked before __init__. The __new__ method is called with the class as its first argument; its responsibility is to return a new instance of that class. Compare this to __init__: __init__ is called with an instance as its first argument, and it doesn't return anything; its responsibility is to initialize the instance.

The other possibly-unfamiliar element is the WeakValueDictionary. In a nutshell, it's a dictionary that deletes its entries if no other variables point to them. When instantiating a Card object, it checks in the Card class's _CardPool to return an existing object, or creates a new Card object if needed.

If you're confused, take a few minutes to play with the code. Insert print statements into __new__ to show you the contents of _CardPool.items() and whether a new object is created. There's a lot of important object orientation concepts at work in a short block of code: inheritance, the difference between classes and objects, references, and overriding.

I've removed the __eq__ and __ne__ calls because two Cards with the same value and suit are the same objects, saving our casino many gigs of precious RAM:

Equality for Python

A few days ago in #chipy, the chat room for the Chicago Python Users Group, we had a chat about how Python determines equality. It's a pretty neat and extensible technique, so I'm going to walk through how I recently used it for playing cards.

Here's the basic Card class. Note that I'm going to totally skip things like error-checking and documentation to keep the example obvious.

values = ('2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A')
suits = ('h', 'c', 'd', 's')

class Card:
    def __init__(self, value, suit):
        self.value, self.suit = value, suit

    def __repr__(self):
        return "<Card: %s%s>" % (self.value, self.card)

Man, does code get short when you don't bother checking for errors. The usage is pretty clear, but there's one odd issue:

Versioning - The Next Big Thing

In the web development world, anyways. So, in the grand scheme of things, maybe not a huge deal to anyone else. Versioning is going to be one of the biggest problems and opportunities there is in web development, and it's going to take us at least five years to get it right.

Actually, let me admit up front that five years is a shot in the dark, and optimistic to boot. If people keep hanging out with bondage and discipline languages like Java and C# that are still catching up to language and framework developments from the 90's it'll take us more like ten years. (Attention Lisp Weenies: Yes, I know you solved every problem forty years ago for certain values of "solved" and "problem" while the rest of us were getting work done.) Not only is versioning a difficult technical problem, it will be difficult to educate programmers in what it is, how it works, and why you'll wish you used about a year after you decided it was too much work.

New Contributor - Peter Harkins

Let's all give a warm welcome to our newest contributor, the incredibly brilliant and good-looking Peter Harkins.

That's right, clap for me -- er, him, clap for him. I'm not writing this about myself. I mean he's not. Crap.

Hi, folks. I'm a new contributor to CodeSnipers. I'll be writing mostly about design and coding, though I may wander into MicroISV territory if any of my side projects should start doing particularly well.

To tell you a little about myself, I'm a 25-year old web developer in Chicago, IL, USA, Earth. I've been programming for about fourteen years, professionally for the last 5.5. My constant obsession is writing code that's just a little bit better, a little bit smarter, a little bit higher-level. Even though the steps I've taken and will be writing about are small, they're a great way to improve code and design every time you touch it.