<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>the corioblog &#187; programming</title>
	<atom:link href="http://www.coriolinus.net/category/geekspeak/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.coriolinus.net</link>
	<description>read, and be entertained</description>
	<lastBuildDate>Sat, 09 Jul 2011 19:53:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>conf.py: One-upping ConfigParser</title>
		<link>http://www.coriolinus.net/2010/11/13/conf-py-one-upping-configparser/</link>
		<comments>http://www.coriolinus.net/2010/11/13/conf-py-one-upping-configparser/#comments</comments>
		<pubDate>Sat, 13 Nov 2010 14:39:13 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Class]]></category>
		<category><![CDATA[Computer programming]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[Creative Commons]]></category>
		<category><![CDATA[Human Interest]]></category>
		<category><![CDATA[Main function]]></category>
		<category><![CDATA[Method]]></category>
		<category><![CDATA[Object-oriented programming]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Perl module]]></category>
		<category><![CDATA[programmer]]></category>
		<category><![CDATA[Software design patterns]]></category>
		<category><![CDATA[software engineering]]></category>
		<category><![CDATA[wb]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=3135</guid>
		<description><![CDATA[There comes a time in every programmer&#8217;s life when they decide that some silly, common library that they use all the time just isn&#8217;t good enough. It takes too many actions, or it feels opaque, or there are obvious features conspicuous in their absence. For me, that time is now, that library is ConfigParser, and [...]]]></description>
			<content:encoded><![CDATA[<p>There comes a time in every programmer&#8217;s life when they decide that some silly, common library that they use all the time just <em>isn&#8217;t good enough</em>. It takes too many actions, or it feels opaque, or there are obvious features conspicuous in their absence. </p>
<p>For me, that time is now, that library is ConfigParser, and the replacement is included below the fold. It&#8217;s called conf, and it means that the only interaction you as a programmer are required to have with your config file is to assign and/or read values to/from it. Assigning and reading look exactly like normal attribute assignment/reading. </p>
<p>Subversion/TRAC string: <a href="https://trac.coriolinus.net/browser/OOconf">https://svn.coriolinus.net/OOconf</a><br />
distutils packaged version: <a href="https://trac.coriolinus.net/browser/OOconf/dist/conf-0.2.0.zip?format=raw">conf-0.2.0</a></p>
<p>As always, I&#8217;m too cheap to pay a thousand dollars for a site certificate, so please ignore any certificate mismatch errors you encounter when viewing the https side of the site. If you don&#8217;t trust me enough to click through, you&#8217;ll still find the current version under the fold.</p>
<p><span id="more-3135"></span></p>
<pre class="brush: python">
import os
import codecs
import json
from ConfigParser import SafeConfigParser

def internal(func):
	def tf(self, *args, **kwargs):
		self.__dict__[&#039;__conf__&#039;].__dict__[&#039;__internal__&#039;] += 1
		try:
			return func(self, *args, **kwargs)
		finally:
			self.__dict__[&#039;__conf__&#039;].__dict__[&#039;__internal__&#039;] -= 1
	return tf

class Section(object):
	def __init__(self, conf, name, fullname=None):
		if fullname is None:
			fullname = name

		self.__dict__[&#039;__conf__&#039;] = conf
		self.__name__ = name
		self.__fullname__ = fullname

		self.__dict__[&#039;subsections&#039;] = set()
		self.__dict__[&#039;attributes&#039;] = set()

		#this lines MUST be the last in __init__
		self.__restrictedvars__ = set((i for i in dir(self) if &#039;__&#039; not in i))

	@internal
	def __setattr__(self, name, value):
		if self.restricted(name):
			if (not self.__conf__.__restrict__) or self.__conf__.__internal__ &gt; 0:
				self.__dict__[name] = value
			else:
				raise AttributeError(&quot;Namespace conflict: %s restricted for Conf use.&quot; % name)
		else:
			self.__conf__.__new_data__ = True
			self.attributes.add(name)
			self.__conf__.__cp__.set(self.__fullname__, name, json.dumps(value))

	@internal
	def __getattr__(self, name):
		if self.restricted(name):
			return self.__dict__[name]
		else:
			return json.loads(self.__conf__.__cp__.get(self.__fullname__, name))

	@internal
	def __delattr__(self, name):
		if self.restricted(name):
			if (not self.__conf__.__restrict__) or self.__conf__.__internal__ &gt; 0:
				del self.__dict__[name]
			else:
				raise AttributeError(&quot;Namespace conflict: %s restricted for Conf use.&quot; % name)
		else:
			self.__conf__.__new_data__ = True
			self.attributes.remove(name)
			self.__conf__.__cp__.remove_option(self.__name__, name)

	@internal
	def restricted(self, name):
		&quot;&quot;&quot;
		This function returns true for all attributes which should be stored locally, not in the
		configuration file proper.
		&quot;&quot;&quot;
		if name.startswith(&#039;__&#039;) or name.endswith(&#039;__&#039;):
			return True
		if name in self.__restrictedvars__:
			return True

		return False

	@internal
	def add_section(self, name):
		fullname = &#039;&#039;.join((self.__fullname__, &#039;.&#039;, name))

		if hasattr(self, name):
			raise ValueError(&quot;Namespace conflict: %s already in use&quot; % fullname)

		if not self.__conf__.__cp__.has_section(fullname):
			self.__conf__.__cp__.add_section(fullname)
		self.subsections.add(name)
		self.__dict__[name] = Section(self.__conf__, name, fullname)
		self.__restrictedvars__.add(name)
		self.__new_data__ = True

	@internal
	def remove_section(self, name):
		fullname = &#039;&#039;.join((self.__fullname__, &#039;.&#039;, name))

		if not hasattr(self, name):
			raise ValueError(&quot;Can&#039;t remove section %s, as it doesn&#039;t exist&quot; % fullname)

		sub = getattr(self, name)
		for subsub in list(sub.subsections):
			sub.remove_section(subsub)

		self.__conf__.__cp__.remove_section(fullname)
		self.subsections.remove(name)
		self.__restrictedvars__.remove(name)
		del self.__dict__[name]
		self.__new_data__ = True

class Conf(Section):
	&quot;&quot;&quot;
	Automatic storage and retrieval of arbitrary values into a config file. 

	Uses type information and automatic reconversions to store a variety of primitive types in a
	perfectly human-readable format. Primitive types are those encodable by the json module.

	Usage:
	&gt;&gt;&gt; from conf import Conf
	&gt;&gt;&gt; conf = Conf() #or Conf(filename, defaultsectionname)
	&gt;&gt;&gt; conf.foo = &#039;hello world&#039;
	&gt;&gt;&gt; conf.bar = 723
	&gt;&gt;&gt; conf.baz = False
	&gt;&gt;&gt; conf.flush()

	[exit, start a new session here]

	&gt;&gt;&gt; conf = Conf()
	&gt;&gt;&gt; conf.foo
	&#039;hello world&#039;
	&gt;&gt;&gt; conf.bar
	723
	&gt;&gt;&gt; conf.baz
	False

	If you want implicit file creation, you need to use a with statement:
	&gt;&gt;&gt; with Conf() as conf:
	...      conf.foo = 2783.1
	...
	&gt;&gt;&gt; del conf
	&gt;&gt;&gt; with Conf() as otherConf:
	...      otherConf.foo
	...
	2783.1
	&quot;&quot;&quot;
	def __init__(self, filename =&#039;.conf&#039;, sectionName=None):
		&quot;&quot;&quot;
		Initialize a new Conf object.
		&quot;&quot;&quot;
		self.__dict__[&#039;__internal__&#039;] = 0
		self.__dict__[&#039;__restrict__&#039;] = False
		#the above is magic; it must come first

		#sanity check
		if sectionName is not None and &#039;.&#039; in sectionName:
			raise ValueError(&quot;Namespace: &#039;.&#039; cannot be part of a section name&quot;)

		#initialize the superclass
		Section.__init__(self, self, sectionName if sectionName is not None else &#039;config&#039;)

		self.__filename__ = filename
		self.__cp__ = SafeConfigParser()

		#load and initialize the configparser
		if os.path.exists(filename):
			with codecs.open(filename, &#039;rb&#039;, &#039;utf8&#039;) as cf:
				self.__cp__.readfp(cf, filename)

		if sectionName is None:
			topLevelSections = [s for s in self.__cp__.sections() if s.count(&#039;.&#039;) == 0]
			if len(topLevelSections) == 1:
				sectionName = topLevelSections[0]
				self.__name__ = sectionName
				self.__fullname__ = sectionName
			else:
				sectionName = &#039;config&#039;

		#create the default section
		if not self.__cp__.has_section(sectionName):
			self.__cp__.add_section(sectionName)

		#load default section attributes
		self.attributes = set(self.__cp__.options(sectionName))

		#load the various sections
		#first, sort them by the number of dots they contain
		secs = [(s.count(&#039;.&#039;), s) for s in self.__cp__.sections() if s != sectionName]
		secs.sort()
		for name in [sec for count, sec in secs]:
			if &#039;.&#039; not in name:
				self.subsections.add(name)
				self.__dict__[name] = Section(self, name)
				self.__dict__[name].attributes = set(self.__cp__.options(name))
				self.__restrictedvars__.add(name)
			else:
				fullname = name
				rest, name = name.rsplit(&#039;.&#039;, 1)
				sec = self
				for part in rest.split(&#039;.&#039;):
					sec = getattr(sec, part)
				sec.subsections.add(name)
				sec.__dict__[name] = Section(self, name, fullname)
				sec.__dict__[name].attributes = set(self.__cp__.options(fullname))
				sec.__restrictedvars__.add(name)

		self.__new_data__ = False

		#this must come last:
		self.__internal__ = 0
		self.__restrict__ = True
		#This is used in combination with the @internal decorator. Each method so decorated
		# increments this variable on entry, and decrements it on exit. They can then check: is
		# __internal__ &gt; 0? If yes, they were called from within this Conf object, and can adjust
		# their behavior accordingly.
		#
		#Note that we initialize it here to 0. When this __init__ exits, it decrements to -1. This
		# is intentional. Since each internal function starts by incrementing it, this means that
		# only if the variable is &gt; 0 was its caller also internal.

	@internal
	def __enter__(self):
		return self

	@internal
	def __exit__(self, exc_type, exc_value, traceback):
		if self.__new_data__:
			self.flush()

	@internal
	def flush(self):
		with codecs.open(self.__filename__, &#039;wb&#039;, &#039;utf8&#039;) as cf:
			self.__cp__.write(cf)
		self.__new_data__ = False

	@internal
	def add_section(self, name):
		&quot;&quot;&quot;
		Create a new section in the conf file. This will become a dotted extension of the conf object.

		For example:
		&gt;&gt;&gt; c = Conf()
		&gt;&gt;&gt; c.foo = &#039;hello world&#039;
		&gt;&gt;&gt; c.add_section(&#039;bar&#039;)
		&gt;&gt;&gt; c.bar.baz = &#039;world says hello&#039;

		The above turns into a config file which looks like this:
		[config]
		foo = hello world

		[bar]
		baz = world says hello
		&quot;&quot;&quot;
		if hasattr(self, name):
			raise ValueError(&quot;Namespace conflict: %s already in use&quot; % name)
		if &#039;.&#039; in name:
			raise ValueError(&quot;Namespace: &#039;.&#039; cannot be part of a section name&quot;)

		if not self.__conf__.__cp__.has_section(name):
			self.__conf__.__cp__.add_section(name)
		self.subsections.add(name)
		self.__dict__[name] = Section(self, name)
		self.__restrictedvars__.add(name)
		self.__new_data__ = True

	@internal
	def remove_section(self, name):
		&quot;&quot;&quot;
		Remove a section and all included data.
		&quot;&quot;&quot;
		if not hasattr(self, name):
			raise ValueError(&quot;Can&#039;t remove section %s, as it doesn&#039;t exist&quot; % name)

		sub = getattr(self, name)
		for subsub in sub.subsections:
			sub.remove_section(subsub)

		self.__cp__.remove_section(name)
		self.subsections.remove(name)
		self.__restrictedvars__.remove(name)
		del self.__dict__[name]
		self.__new_data__ = True
</pre>
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/Text" property="dct:title" rel="dct:type">conf.py</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://coriolinus.net" property="cc:attributionName" rel="cc:attributionURL">coriolinus</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="http://www.coriolinus.net/contact/" rel="cc:morePermissions">http://www.coriolinus.net/contact/</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2010/11/13/conf-py-one-upping-configparser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>keeping up</title>
		<link>http://www.coriolinus.net/2010/04/13/keeping-up/</link>
		<comments>http://www.coriolinus.net/2010/04/13/keeping-up/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 09:34:47 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[army]]></category>
		<category><![CDATA[civilian contractor]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[Cross-platform software]]></category>
		<category><![CDATA[Data management]]></category>
		<category><![CDATA[Database management systems]]></category>
		<category><![CDATA[Databases]]></category>
		<category><![CDATA[IBM software]]></category>
		<category><![CDATA[Microsoft SQL Server]]></category>
		<category><![CDATA[MSSQL query designer]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=3053</guid>
		<description><![CDATA[Today I got to code to solve a problem. The Army&#8217;s bit of code which moved flight records from the maintenance database into the pilot records database broke, and I got to write a replacement. It&#8217;s trivial code, really: take a fairly complex SQL join generated by MSSQL, and write its results to an XML [...]]]></description>
			<content:encoded><![CDATA[<p>Today I got to code to solve a problem. The Army&#8217;s bit of code which moved flight records from the maintenance database into the pilot records database broke, and I got to write a replacement. It&#8217;s trivial code, really: take a fairly complex SQL join generated by MSSQL, and write its results to an XML file using a particular schema. Still, I got really, stupidly excited about this. </p>
<p>I also learned some things:</p>
<ol>
<li>I am very, very out of practice. More than four hours into the exercise, I was still debugging. The bugs were things like MSSQL Optional Feature Not Implemented, not actual logic errors, but still. That&#8217;s too long given the complexity of the task.</li>
<li>I have a lot of fun coding. In a basically unprecedented move, I was delaying leaving work until the guy whose office I was borrowing made me leave so he could lock up. Especially given that I&#8217;d had an 11 hour day at that point, this is a significant development.</li>
<li>For all that I rag on MS products, the MSSQL query designer really does take a lot of work out of the process of writing complex queries.</li>
</ol>
<p>Actually, 90 minutes into the exercise, a civilian contractor came by and worked magic and solved the problem for which I was writing code in the first place. I kept working, using the excuse that my version will be more featureful than the Army&#8217;s, and that by having the source to it the Army will benefit. The real reason is much simpler: I&#8217;m having way too much fun to just give this project up. I am perpetually at the 50% mark and working rapidly towards completion; I&#8217;m not going to let this just escape me. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2010/04/13/keeping-up/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pictures from Last Night</title>
		<link>http://www.coriolinus.net/2010/03/28/pictures-from-last-night/</link>
		<comments>http://www.coriolinus.net/2010/03/28/pictures-from-last-night/#comments</comments>
		<pubDate>Sun, 28 Mar 2010 13:16:07 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[life things]]></category>
		<category><![CDATA[photos]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[B-boy]]></category>
		<category><![CDATA[Breakdance]]></category>
		<category><![CDATA[Flickr]]></category>
		<category><![CDATA[Hip hop dance]]></category>
		<category><![CDATA[Hospitality/Recreation]]></category>
		<category><![CDATA[Nerd]]></category>
		<category><![CDATA[Slang]]></category>
		<category><![CDATA[Sociology]]></category>
		<category><![CDATA[World Wide Web]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=3022</guid>
		<description><![CDATA[It was an interesting night: I was at a B-Boying (breakdancing for those not down with the slang) competition. As a second date, it was quite fun; as an event to photograph, it was a challenge; as a skill, it was intimidating. More images here, at the flickr set. Statistics, because I am a nerd: [...]]]></description>
			<content:encoded><![CDATA[<p>It was an interesting night: I was at a B-Boying (breakdancing for those not down with the slang) competition. As a second date, it was quite fun; as an event to photograph, it was a challenge; as a skill, it was intimidating. </p>
<p><a href="http://www.flickr.com/photos/coriolinus/sets/72157623594736397/detail/" title="horizontal kick by coriolinus, on Flickr"><img src="http://farm3.static.flickr.com/2778/4469898744_efea62dca0_b.jpg" width="1024" height="666" alt="horizontal kick" /></a></p>
<p>More images <a href="http://www.flickr.com/photos/coriolinus/sets/72157623594736397/detail/">here</a>, at the flickr set.</p>
<hr align="center" width="50%" />
<em>Statistics, because I am a nerd:</em><br />
Photos taken: 178<br />
Photos discarded as terrible: 80<br />
Good photos: 7<br />
Programs written to get rid of the raws left over after discarding the terrible photos: <a href="https://trac.coriolinus.net/browser/rawremove/rawremove.py">1</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2010/03/28/pictures-from-last-night/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python 3.0 Released</title>
		<link>http://www.coriolinus.net/2008/12/05/python-30-released/</link>
		<comments>http://www.coriolinus.net/2008/12/05/python-30-released/#comments</comments>
		<pubDate>Sat, 06 Dec 2008 00:03:18 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=2714</guid>
		<description><![CDATA[3.0 is finally out. Go get it. Say you took all the programming languages I have ever encountered and put them into a table. If you were to assign a column to ease of use, a column to language power, and a third column to the product of the previous two columns, then reverse sort [...]]]></description>
			<content:encoded><![CDATA[<p>3.0 is finally <a href="http://www.python.org/download/releases/3.0/">out</a>. Go get it.</p>
<p>Say you took all the programming languages I have ever encountered and put them into a table. If you were to assign a column to ease of use, a column to language power, and a third column to the product of the previous two columns, then reverse sort the table by the last column, Python would be the first language in the table.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2008/12/05/python-30-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Small Basic</title>
		<link>http://www.coriolinus.net/2008/11/09/small-basic/</link>
		<comments>http://www.coriolinus.net/2008/11/09/small-basic/#comments</comments>
		<pubDate>Mon, 10 Nov 2008 03:50:34 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Microsoft Corporation]]></category>
		<category><![CDATA[Visual Basic]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=2687</guid>
		<description><![CDATA[Microsoft just released another .NET language: Small Basic, designed to get MS back into the business of teaching programming. I have to laugh at parts of the release document. For example, the claim that programming languages started simple and easy to learn, and that the high-level concepts of modern languages discourage people from learning to [...]]]></description>
			<content:encoded><![CDATA[<p>Microsoft just released another .NET language: <a href="http://download.microsoft.com/download/9/0/6/90616372-C4BF-4628-BC82-BD709635220D/Introducing%20Small%20Basic.pdf">Small Basic</a>, designed to get MS back into the business of teaching programming.</p>
<p>I have to laugh at parts of the release document. For example, the claim that programming languages started simple and easy to learn, and that the high-level concepts of modern languages discourage people from learning to code. &#8220;Hello World&#8221; is a one-liner only in a high-level language; it&#8217;ll take a beginner a few days of work and tons of documentation to accomplish in assembly. I also loved the section titled &#8220;Rules for naming Variables&#8221;: &#8220;[TODO]&#8221;</p>
<p>In general, this looks like a rehash of QBasic, of which all the warts are still present. The language lesson introduces GOTO long before talking about subroutines. Subs (not functions) access and modify global variables, and are limited to the current file&#8217;s scope. The major differences seem to be that most of the library functions have been rewritten in an object-oriented style and additional libraries for GUI stuff and Turtle programming have been added. Even though the library uses objects, the user has no way of writing their own.</p>
<p>I can see some junior coder at Microsoft doing this as a project for promotion points. It very much feels like a student project. However, I can&#8217;t see any programmer using it to actually teach programming. Small Basic might be useful if your ambition is to one day work up to Visual Basic as an enterprise programming language, but people interested in learning modern programming techniques would be better advised to look elsewhere for their first language.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2008/11/09/small-basic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iTunes 7.7 COM bug</title>
		<link>http://www.coriolinus.net/2008/07/22/itunes-77-com-bug/</link>
		<comments>http://www.coriolinus.net/2008/07/22/itunes-77-com-bug/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 03:07:05 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[brain flotsam]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[iTunes]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=2190</guid>
		<description><![CDATA[I&#8217;ve had a little utility for quite some time now that I use mainly to let the iTunes&#8217; current song play through its end, then stop. It&#8217;s one feature from Winamp that I couldn&#8217;t deal without. Quite recently, I upgraded to iTunes 7.7. My little utility stopped working. When I finally got around to looking [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had <a href="https://trac.coriolinus.net/browser/PyTunes">a little utility</a> for quite some time now that I use mainly to let the iTunes&#8217; current song play through its end, then stop. It&#8217;s one feature from Winamp that I couldn&#8217;t deal without.</p>
<p>Quite recently, I upgraded to iTunes 7.7. My little utility stopped working. When I finally got around to looking into the error, I found this:</p>
<pre class="brush: python">
Python 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)] on win32
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; import win32com.client
&gt;&gt;&gt; itunes = win32com.client.Dispatch(&quot;iTunes.Application&quot;)
&gt;&gt;&gt; help(itunes._print_details_)
Help on method _print_details_ in module win32com.client.dynamic:

_print_details_(self) method of win32com.client.CDispatch instance
Debug routine - dumps what it knows about an object.

&gt;&gt;&gt; itunes._print_details_()
AxDispatch container iTunes.Application
Methods:
Props:
Get Props:
Put Props:
&gt;&gt;&gt;
</pre>
<p>You&#8217;ll note that as far as COM is concerned, iTunes no longer publishes any methods or properties in its only externally instantiable interface. In other words, it&#8217;s become a black box with no inputs or outputs. You can tell that it&#8217;s there, but you can&#8217;t interact with it in any way.</p>
<p>I may try again in some other language; it&#8217;s possible that iTunes is somehow no longer compatible with the python win32com implementation, but still works with others. Still, it&#8217;s annoying.</p>
<p>[edit 20080914]</p>
<p>Things work nicely again in iTunes 8.0.0.35; hopefully they stay working this time.</p>
<p>Also, I discovered that my code example above is not very helpful. It seems that the methods in the win32com client object are lazily added the first time they are called, so _print_details_() will only ever show methods that have already been called successfully. I suppose I should be happy that they implemented COM support at all, instead of being annoyed that introspection doesn&#8217;t work as well as python has accustomed me to.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2008/07/22/itunes-77-com-bug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Protocol Buffers</title>
		<link>http://www.coriolinus.net/2008/07/08/protocol-buffers/</link>
		<comments>http://www.coriolinus.net/2008/07/08/protocol-buffers/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 01:14:23 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[misc.link]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[I/O stream]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=2167</guid>
		<description><![CDATA[Subtitle: The good, the bad, and the&#8230; no, wait; this is a Google project. XML and Java have the same sort of flavor to them: they&#8217;re reasonably good and very widely used; they&#8217;re the sort of product that design committees everywhere aspire to create. Their flaws only really become visible after something better comes along. [...]]]></description>
			<content:encoded><![CDATA[<p>Subtitle: The good, the bad, and the&#8230; no, wait; this is a Google project.</p>
<p>XML and Java have the same sort of flavor to them: they&#8217;re reasonably good and very widely used; they&#8217;re the sort of product that design committees everywhere aspire to create. Their flaws only really become visible after something better comes along. In Java&#8217;s case, Python demonstrated that a whole lot of the structure and required text that gives Java code its rigidity can be stripped away, leaving a language that&#8217;s a joy to develop in. However, there hasn&#8217;t been an analogous improvement on XML.</p>
<p>Until yesterday.</p>
<p>Protocol Buffers have a non-descriptive name; I had no idea what to expect when I clicked <a href="http://google-opensource.blogspot.com/2008/07/protocol-buffers-googles-data.html">the link to the announcement</a> that Google put out. As it turns out, they&#8217;re a generic data serialization format (much like XML), except without all the human-readability business that so bloats actual XML. From the announcement:</p>
<blockquote><p>Protocol Buffers allow you to define simple data structures in a special definition language, then compile them to produce classes to represent those structures in the language of your choice. These classes come complete with heavily-optimized code to parse and serialize your message in an extremely compact format. Best of all, the classes are easy to use: each field has simple &#8220;get&#8221; and &#8220;set&#8221; methods, and once you&#8217;re ready, serializing the whole thing to – or parsing it from – a byte array or an I/O stream just takes a single method call.</p></blockquote>
<p>In case you missed that, <em>all you have to write is the schema</em>. All the encoding and decoding crap that you have to wade through in XML has already been abstracted away; they generate classes to do that for you. This is, in fact, cooler than sliced bread.</p>
<p>Of course, there <a href="http://code.google.com/apis/protocolbuffers/docs/overview.html#whynotxml">do exist times</a> when XML might better serve your needs:</p>
<blockquote><p>However, protocol buffers are not always a better solution than XML – for instance, protocol buffers would not be a good way to model a text-based document with markup (e.g. HTML), since you cannot easily interleave structure with text. In addition, XML is human-readable and human-editable; protocol buffers, at least in their native format, are not. XML is also – to some extent – self-describing. A protocol buffer is only meaningful if you have the message definition (the <code>.proto</code> file).</p></blockquote>
<p>In my experience, the human-readability and self-documentation inherent in XML have always been bonus features not essential to the core mission, which was getting data from Point A to Point B. However, I&#8217;ve had to spend countless hours wrangling with DOM and SAX, dealing with the problem of getting the data into and out of that intermediate form.</p>
<p>There is one wart that I noticed: you still have to create and read the Messages entirely distinctly from your own native class structure. The natural thing to do, if you want to use this to serialize and deserialize a class, would be just to put all the members into the Message definition and put the methods into a subclass of the generated class. However, that is <a href="http://code.google.com/apis/protocolbuffers/docs/reference/python-generated.html#message">expressly forbidden</a>. All is not lost, though: all you really need, at simplest, is a pair of methods like this:</p>
<pre class="brush: python">
class AClass(object):
     ...
     def toPBuff(self):
          out = AClassPBuff()
          for member in dir(self):
               if not (callable(member) or &#039;__&#039; in member or member in self.__excludeFromSerialize):
                    setattr(out, member, getattr(self, member))
          return out

     @classmethod
     def fromPBuff(cls, pBuff):
          out = AClass()
          for member in dir(out):
               if not (callable(member) or &#039;__&#039; in member or member in self.__excludeFromSerialize):
                    setattr(out, member, getattr(pBuff, member))
          return out
</pre>
<p>In short, even if only in terms of making efficient use of developer time, this is already an awesome project. Once you count in that it is also faster and slimmer than the alternatives, this becomes astonishingly cool. Expect it to be making appearances in my code from now on.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2008/07/08/protocol-buffers/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>I made a toy</title>
		<link>http://www.coriolinus.net/2008/07/06/i-made-a-toy/</link>
		<comments>http://www.coriolinus.net/2008/07/06/i-made-a-toy/#comments</comments>
		<pubDate>Mon, 07 Jul 2008 02:16:01 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[brain flotsam]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[online documentation]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=2163</guid>
		<description><![CDATA[It&#8217;s not very much*, but it represents my first tentative steps towards doing something visual with PyGame. &#8220;But,&#8221; you object, &#8220;what happened to that C++ project you were working on?&#8221; Basically, I got bored**. I have a fairly high tolerance for doing background research before jumping into a project, but the sheer volume of required [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.coriolinus.net/wp-content/uploads/2008/07/drunkard.png"><img class="alignright size-medium wp-image-2164" title="drunkard" src="http://www.coriolinus.net/wp-content/uploads/2008/07/drunkard-300x300.png" alt="Very simple drunkard\'s walk simulator" width="300" height="300" /></a><a href="https://trac.coriolinus.net/browser/lrnpygame/drunkard.py">It&#8217;s not very much</a>*, but it represents my first tentative steps towards doing something visual with <a href="http://www.pygame.org/" target="_blank">PyGame</a>.</p>
<p>&#8220;But,&#8221; you object, &#8220;what happened to that C++ project you were working on?&#8221;</p>
<p>Basically, I got bored**. I have a fairly high tolerance for doing background research before jumping into a project, but the sheer volume of required reading to even have an idea of how to start is fairly daunting. I just figured it was better to code something than walk away entirely.</p>
<p>I was going to stay a little bit on focus, write a spinning globe in C++ using OpenGL. Then I started looking into online documentation and found absolutely nothing that gave me a starting point. I couldn&#8217;t even find a website that told me which header files to include to get at the API, let alone documentation of the API itself.</p>
<p>Clearly, that&#8217;s a project for another day. Taking the second best option, I decided to see what was doable with PyGame. I&#8217;d heard the name before without having actually used it for anything; it was only natural to see what it could do. As it turns out, it focuses more on 2d graphics than 3d. A rotating image of a globe would amuse nobody, so I changed my design goal, and ended up with this.</p>
<p>Playing with graphics, once you get past the initial hurdles, is kind of fun. There may be more of this later.</p>
<hr width="30%" align="left" />
<small>* Firefox 3 gets <em>really upset</em> that I&#8217;m using a generic certificate borrowed from my webhost to authenticate for HTTPS transactions. If it gives you an anti-spam warning because the certificate doesn&#8217;t match, just add an exemption. I haven&#8217;t gone through the hoops to get my own site certificate, and I promise not to ask you for your credit card or otherwise try to misuse the trust implied by such an exemption.</p>
<p>** &#8220;But what about the computer games and novels you can be trusted to fritter away your time with before starting any productive work at all?&#8221; <a href="http://en.wikipedia.org/wiki/X-COM:_UFO_Defense">XCOM</a> crashed one time too many, its <a href="http://www.projectxenocide.com/">open-source replacement</a> is years from playability, and I thought it&#8217;d be a neat feather in my hat if I could get some measurable percentage done on my own replacement today. As things turned out, that feather eluded my grasp.</small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2008/07/06/i-made-a-toy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>virtual insanity</title>
		<link>http://www.coriolinus.net/2008/06/25/virtual-insanity/</link>
		<comments>http://www.coriolinus.net/2008/06/25/virtual-insanity/#comments</comments>
		<pubDate>Thu, 26 Jun 2008 00:23:31 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=2156</guid>
		<description><![CDATA[I&#8217;m trying to remain enthusiastic about C++. I&#8217;ve been pushing through the books, trying to gain enough fluency to start pushing forward on a real project. Every once in a while I&#8217;d run across something weird, like the necessity of explicitly writing a copy constructor and overloading the assignment operator of any non-trivial class, but [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m trying to remain enthusiastic about C++. I&#8217;ve been pushing through the books, trying to gain enough fluency to start pushing forward on a real project. Every once in a while I&#8217;d run across something weird, like the necessity of <a href="http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)">explicitly writing a copy constructor and overloading the assignment operator</a> of any non-trivial class, but those things seemed like quirks that would be easy enough to live with.</p>
<p>Then I got to the part about the <tt>virtual</tt> keyword.</p>
<p>In every other <a href="http://en.wikipedia.org/wiki/Object_oriented">object-oriented language</a> I&#8217;ve ever learned, complete support for <a href="http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Ad-hoc_polymorphism">polymorphism</a> was just assumed. If you subclass some class and override some of its methods, then naturally whenever you call those methods on an instance of your subclass, you get your overrides. I can&#8217;t even describe this without sounding tautological, because all the terminology in OOP just assumes that things work this way. Polymorphism is such a fundamental concept that I never really considered that a language would call itself Object Oriented without supporting it inherently.</p>
<p>Then I got to C++. Consider this code:</p>
<pre class="brush: cpp">
class A {
public:
     void method();
};

class B : public A {
public:
     void method();
};

void demo_fail();

void A::method() {
     std::cout &lt;&lt; &quot;    A::method() called\n&quot;;
}

void B::method() {
     std::cout &lt;&lt; &quot;    B::method() called\n&quot;;
}

void demo_fail() {
     A *a = new A();
     A *b = new B();

     std::cout &lt;&lt; &quot;Calling a-&gt;method()...\n&quot;;
     a-&gt;method();
     std::cout &lt;&lt; &quot;Calling b-&gt;method()...\n&quot;;
     b-&gt;method();
     std::cout &lt;&lt; &quot;\n...What?\n&quot;;
}
</pre>
<p>You&#8217;d expect the above code to happily call A&#8217;s method, then B&#8217;s. Instead, the output looks like this:</p>
<p><a href="http://www.coriolinus.net/wp-content/uploads/2008/06/demo_fail.png"><img class="alignnone size-full wp-image-2157" title="demo_fail" src="http://www.coriolinus.net/wp-content/uploads/2008/06/demo_fail.png" alt="this is not the expected output" width="276" height="130" /></a></p>
<p>It turns out that C++ does support polymorphism; it&#8217;s just that <a href="http://en.wikipedia.org/wiki/Bjarne_Stroustrup">someone</a> decided not to enable it by default. The <tt>virtual</tt> keyword is the key here; by adding it to the prototype of the method of the superclass, things start working again:</p>
<pre class="brush: cpp">
class Alpha {
public:
     virtual void method();
};

class Bravo : public Alpha {
public:
     void method();
};

void demo_succeed();

void Alpha::method() {
     std::cout &lt;&lt; &quot;    Alpha::method() called\n&quot;;
}

void Bravo::method() {
     std::cout &lt;&lt; &quot;    Bravo::method() called\n&quot;;
}

void demo_succeed() {
     Alpha *alpha = new Alpha();
     Alpha *bravo = new Bravo();

     std::cout &lt;&lt; &quot;Calling alpha-&gt;method()...\n&quot;;
     alpha-&gt;method();
     std::cout &lt;&lt; &quot;Calling bravo-&gt;method()...\n&quot;;
     bravo-&gt;method();
     std::cout &lt;&lt; &quot;\nThe |virtual| keyword is essential.\n&quot;;
}
</pre>
<p><a href="http://www.coriolinus.net/wp-content/uploads/2008/06/demo_succeed.png"><img class="alignnone size-full wp-image-2158" title="demo_succeed" src="http://www.coriolinus.net/wp-content/uploads/2008/06/demo_succeed.png" alt="That is more expected" width="332" height="143" /></a></p>
<p>The problem here isn&#8217;t so much that you need an arbitrary keyword to enable one of the fundamentals of OOP; it&#8217;s where that keyword has to go. Useful programming in the modern era depends on libraries of code that the individual coder doesn&#8217;t need, or want, to maintain. One of the nice things about OOP is that you can use a library as long as it&#8217;s useful, and even a bit longer: just subclass and extend until you have all the functionality you need. In C++, that only works if the library author has correctly anticipated exactly which functions you will need to override. In practice, this means that the author probably just stuck the virtual keyword onto every public and protected function, neatly negating the tiny compiler optimization that was the whole point of not making the &#8216;virtual&#8217; behavior the default.</p>
<p>I have to admit that I am starting to dread getting to the section on exceptions. According to a friend of mine, C++ exceptions are hacktastic.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2008/06/25/virtual-insanity/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>fibb.cpp</title>
		<link>http://www.coriolinus.net/2008/06/20/fibbcpp/</link>
		<comments>http://www.coriolinus.net/2008/06/20/fibbcpp/#comments</comments>
		<pubDate>Fri, 20 Jun 2008 16:58:23 +0000</pubDate>
		<dc:creator>coriolinus</dc:creator>
				<category><![CDATA[brain flotsam]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.coriolinus.net/?p=2154</guid>
		<description><![CDATA[Expressed here as a tag cloud. The source code itself is nothing special; it&#8217;s just an easy way to test my knowledge of C++ as it grows.]]></description>
			<content:encoded><![CDATA[<p>Expressed here as a tag cloud. The source code itself is nothing special; it&#8217;s just an easy way to test my knowledge of C++ as it grows.</p>
<p><a title="Wordle: fibb.cpp" href="http://wordle.net/gallery/03817/fibb.cpp"><img style="padding:4px;border:1px solid #ddd" src="http://wordle.net/thumb/03817/fibb.cpp" alt="" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.coriolinus.net/2008/06/20/fibbcpp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

