<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Site Perceptive</title>
	
	<link>http://www.jmcneil.net</link>
	<description>Web Infrastructure Systems, Deployments, and Technologies.</description>
	<lastBuildDate>Sat, 05 Mar 2011 19:34:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/WebInfrastructureSystemsDeploymentsAndTechnologies" /><feedburner:info uri="webinfrastructuresystemsdeploymentsandtechnologies" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Learning Go (and reflect-ing on what’s possible, too)</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/qNO5DqgJUqQ/</link>
		<comments>http://www.jmcneil.net/2011/02/learning-go-and-reflect-ing-on-whats-possible-too/#comments</comments>
		<pubDate>Thu, 24 Feb 2011 05:53:35 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=289</guid>
		<description><![CDATA[It&#8217;s been a few days since my last Go post; my apologies. I know everyone out there was feverishly clicking refresh. Relax my babies, there&#8217;s more content on the way. This time, we&#8217;re going to look into the reflect package, which provides the introspection support found in Go. If you&#8217;ll recall, before my last post, [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been a few days since my last Go post; my apologies. I know everyone out there was feverishly clicking refresh. Relax my babies, there&#8217;s more content on the way. This time, we&#8217;re going to look into the reflect package, which provides the introspection support found in Go.</p>
<p>If you&#8217;ll recall, before my <a href="http://www.jmcneil.net/2011/02/learning-go-and-serializing-objects-with-it-too/">last post</a>, my intention was to cover the Go RPC functionality.  I ran into a problem in that the gob package was used internally and I did not yet understand it.  Well, as it turns out, the reflect package is also used. Values are inspected and translated into corresponding gob data. So this time, we&#8217;ll look at reflection within Go.  This is an interesting topic as it not only prepares us for an upcoming RPC post, but it also really solidifies understanding of the Go type system.</p>
<p>Also, realize that I&#8217;m not an expert on Go. If you happen to be one with your Go-Fujitsu and you spot something incorrect (or even perhaps something not idiomatic), please leave a comment. That will help make me an expert!</p>
<h2>The Inspected Code</h2>
<p>In this example, we&#8217;ll dial back down to one source module, it&#8217;s just easier that way.  We&#8217;ll be using the little <em>gogogo </em>command that we created in the <a href="http://www.jmcneil.net/2011/02/learning-go-and-reading-tar-files-with-it-too/">first Go post</a>.  The first thing we&#8217;ll do is create a small collection of types and methods such that we can see what each component looks like when introspected. Here&#8217;s the source that we&#8217;ll actually be exploring at run time.</p>
<pre>package main

import "reflect"
import "log"

type MailMessage struct {
  subject string
  from string
  to string
  body string
  high_priority bool
}

/* Create a new mail message. */
func NewMailMessage(subject string, from string, to string) (*MailMessage) {
  return &amp;MailMessage{subject, from, to, "", false}
}

/* Set the message body. */
func (m *MailMessage)SetBody(body string) {
  m.body = body
}

/* Set message priority. */
func (m *MailMessage)SetPriority(high bool) {
  m.high_priority = high
}

/* Send the message */
func (m MailMessage) SendMessage() (bool) {
  log.Printf("Message to %s has been sent\n", m.to)
  return true
}

/* Typedef 'int' to a new MessagesSent type. */
type MessagesSent int</pre>
<p>Note that at the top of this listing we also declare our package name and include the necessary import statements.  If you&#8217;re following along and wish to compile, then you&#8217;ll wish comment out the line importing reflect as we&#8217;re not using it yet. As an aside, I&#8217;m not sure I like that feature of Go just yet.</p>
<p>A few notes on this example here.</p>
<ol>
<li>We define a new type, which is based on the structure. The new type contains a series of elements.</li>
<li>We define three methods and one function.  Two of the methods take a pointer to a MailMessage structure, whereas the third simply takes a MailMessage structure itself.</li>
<li>We&#8217;re not doing anything. Nothing. This is a highly contrived example meant to highlight reflection. We&#8217;ll tackle the SMTP package down the road a little bit, you know, once we finally get that RPC stuff out of the way.</li>
</ol>
<p>Great. Now that we have enough code that does nothing whatsoever, we&#8217;ll write some code that does something (with nothing). First, a bit of a detour.</p>
<h2>The Type Switch</h2>
<p>First, we&#8217;ll look at what Go deems the &#8220;Type Switch.&#8221;  This gives us a mechanism, via a special syntax switch statement, to chose a code branch based on the underlying type of the object.   Consider the following listing.</p>
<pre>package main

import "log"

func main() {
  x := 1

  switch x_type := x.(type) {
    case int:
      log.Println("It Was An Integer")
     }
}</pre>
<p>This looks simple enough. Given x, we only want to print something if it is indeed an integer type. That special dot-type syntax you see above is what qualifies this as a type switch.  However, take a look at what happens when we try to compile this code.</p>
<pre>$ 6g type_switch.go
type_switch.go:8: cannot type switch on non-interface value x (type int)
$</pre>
<p>That&#8217;s slightly confusing.  It turns out that, in this case, x is being used as a object with a concrete type of integer. That is, it&#8217;s not being referenced via an interface.  If we update the code, we can get the desired result.</p>
<pre>package main

import "log"

func TypeSwitcher(v interface{}) {
   switch v_type := v.(type) {
    case int:
      log.Println("It Was An Integer")
   }
}

func main() {
  TypeSwitcher(1)
}</pre>
<p>Now, before we run this, note the <em>interface{} </em>type. That&#8217;s an empty interface. Empty interfaces can stand in for everything. Let&#8217;s build this again and give it a run, it should now print out what we&#8217;re expecting.</p>
<pre>$ gogogo type_switch.go
2011/02/23 22:54:02 It Was An Integer</pre>
<p>So, now you understand what a type switch is and how decisions based on type can be made in Go. However, what if we&#8217;re not checking against an interface? Or, rather, what if we want to know a little bit more about an object? Perhaps, say, how many fields a structure has? That&#8217;s where reflection comes in.</p>
<h2>The Reflecting Code</h2>
<p>So, like we&#8217;ve done in a few other examples, we&#8217;ll just dump the entire listing here and then walk through it afterwards.  There are quite a few new elements here. Hang in there, we&#8217;ll explain them all.</p>
<pre>/* Pull info we care about from reflect.Type */
func GetTypeInfo(t reflect.Type) (string, reflect.Kind, int) {
  return t.Name(), t.Kind(), t.NumMethod()
}

/* Print information about a reflect.Value. */
func ReflectOnValue(v reflect.Value) {
  /* Nothing to do on a nil. */
  if v == nil {
    log.Println("nil value, nothing to do")
    return
  }

  /* Pull the information we require about the Type. */
  name, kind, methods := GetTypeInfo(v.Type())

  /* Now type switch and extract the Value Info. */
  switch v := v.(type) {

    case *reflect.StructValue:
      log.Printf("Discovered %s/%s that has %d fields and %d methods.\n",
        kind, name, v.NumField(), methods)

    case *reflect.PtrValue:
      log.Printf("Discovered a pointer with %d methods, dereferencing...\n", methods)
      ReflectOnValue(v.Elem())

    default:
      log.Printf("Found %s/%s with %d methods.\n", kind, name, methods)
  }
}

/* Make anything an interface. */
func PrintValueData(i interface{}) {
  ReflectOnValue(reflect.NewValue(i))
}</pre>
<p>Alright! This code is responsible for digging into the details of our objects and reporting what it finds.  Let&#8217;s walk through it (almost) line by line and examine exactly what&#8217;s going on.</p>
<ul>
<li>The GetTypeInfo function takes a single argument, a reflect.Type, and returns a string, a reflect.Kind, and an integer value.  This little function returns the name of the type in question, the underlying kind, and the number of methods associated with this type in receiver context.</li>
<li>The ReflectOnValue function takes a reflect.Value object v and returns nothing.</li>
<li>First, if v is nil, we simple print that out and return. There&#8217;s no reason to go any further.</li>
<li>Next, we call GetTypeInfo and pull information about this <strong>value&#8217;s </strong>corresponding <strong>type. </strong>That&#8217;s important. In short, this means that each value has a type that contains information such as which methods are associated with it.</li>
<li>Next up, another type switch. This time, however, we&#8217;re switching on the reflect value and not the original value. This allows us to branch according to what the value is.</li>
<li>The first option is a *reflect.StructValue. So, if v&#8217;s type is pointer-to-struct-value, then we&#8217;ll print out the name of the struct, the fact that it is a struct, the number of fields associated with it, and the number of methods it has.  There are calls which allow us to individually access each field by name and number, and to access individual methods as well. We skim over that in this example, however.</li>
<li>The next option is very interesting &#8211; *reflect.PtrValue. Or, in English, a pointer to a pointer value. This is not the same as a pointer to a pointer! Since pointer types can have methods associated with them, we print the number here. Next, we dereference the pointer via &#8220;pointer.Elem()&#8221; and recursively call ourself.   This implies that pointers aren&#8217;t true pointers, rather, a flavor of smart pointer.</li>
<li>The last thing we do in this function is print any &#8220;standard&#8221; types, followed by the number of methods they have associated with them.</li>
<li>Finally, we have PrintValueData. This little helper function simply translates any given value into a reflect.Value, to allow for processing.</li>
</ul>
<h2>The Driver</h2>
<p>Our goal here is to see how different types and values are viewed by the Go system.  We create a series of variables in our main method and send them to our PrintValueData function.</p>
<pre>func main() {
  /* Mail Message Objects */
  m_ptr := NewMailMessage("subject", "from", "to")
  m_std := MailMessage{"subject", "from", "to", "body", false}

  var counter MessagesSent

  /* Print out Information about each. */
  PrintValueData(0)
  PrintValueData(nil)
  PrintValueData(NewMailMessage)
  PrintValueData(m_std)
  PrintValueData(&amp;m_ptr)
  PrintValueData(counter)
}</pre>
<h2>Running the Application</h2>
<p>Now we have a complete application.  Let&#8217;s see what happens when we run it.</p>
<pre>$ gogogo reflect.go
2011/02/24 00:30:45 Found int/int with 0 methods.
2011/02/24 00:30:45 nil value, nothing to do
2011/02/24 00:30:45 Found func/ with 0 methods.
2011/02/24 00:30:45 Discovered struct/MailMessage that has 5 fields and 1 methods.
2011/02/24 00:30:45 Discovered a pointer with 0 methods, dereferencing...
2011/02/24 00:30:45 Discovered a pointer with 3 methods, dereferencing...
2011/02/24 00:30:45 Discovered struct/MailMessage that has 5 fields and 1 methods.
2011/02/24 00:30:45 Found int/MessagesSent with 0 methods.
$</pre>
<p>Wow, neat. This output is almost what we expected.  Let&#8217;s again go through this line-by-line and look at why we&#8217;ve got what we have. Don&#8217;t worry if method information seems a little odd to you, we&#8217;ll double back to that afterwards.</p>
<ol>
<li>Handled by our default case. This is simply an integer with zero methods.</li>
<li>Handled by our nil test.</li>
<li>Handled by our default handler. Go identifies it as a function (with no type name) that has zero of its own methods.</li>
<li>Handled by our structure case. We pass in m_std in our main function, which is a pass-by-value function. Go tells us that this structure has five fields and one method associated with it.</li>
<li>Go finds a pointer with zero methods attached to it, and dereferences.</li>
<li>Go finds a pointer with one three methods attached to it, and dereferences.</li>
<li>Go uncovers what we pointed to by &amp;m_ptr (the address of a pointer to a structure of kind MailMessage). It correctly prints the same information as noted on line four.</li>
<li>Go prints that we have a type MessagesSent with a underlying kind of int, with zero attached methods.</li>
</ol>
<p>Ok, what&#8217;s wrong with this picture? Anyone paying attention? We defined two methods that take a pointer to a MailMessage and one method that takes a MailMessage by value. However, when we dereferenced down to a MailMessage structure, we only accounted for one method. At the same time, we have a pointer (m_ptr after dereferencing &amp;m_ptr), that has three methods! Why?</p>
<p>So, in Go, a pointer to a type&#8217;s set of methods is the union of all methods both on the pointer type as well as the pointed-to type. So, *MailMessage has methods SetBody, SetPriority, and SendMessage associated with it. Of those methods, only SendMessages takes a MailMessage by value, thus it only has one method associated with it.</p>
<h2>Final Thoughts</h2>
<p>So, at this point, we&#8217;ve covered a bit about reflection. The Go documentation on this is slightly sparse.  I pieced this entry together using both the <a href="http://golang.org/pkg/reflect/">Go reflect documentation</a>, and the source code to the <a href="http://golang.org/pkg/json/">Go json module</a>. So, if I&#8217;m off base on anything, please leave a comment and correct me.</p>
<p>Next, it is possible to dynamically dispatch methods using the Call method of a reflect.FuncValue object. This method takes a slice of reflect.Value and returns a slice of reflect.Value. Rigging this up would be an interesting experiment.</p>
<p>Lastly, it is not possible in Go to create new types at runtime.</p>
<p>&nbsp;</p>

<p><a href="http://feedads.g.doubleclick.net/~a/0CUZap13xOI-Mxa1ibpOUcab7vI/0/da"><img src="http://feedads.g.doubleclick.net/~a/0CUZap13xOI-Mxa1ibpOUcab7vI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/0CUZap13xOI-Mxa1ibpOUcab7vI/1/da"><img src="http://feedads.g.doubleclick.net/~a/0CUZap13xOI-Mxa1ibpOUcab7vI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/qNO5DqgJUqQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2011/02/learning-go-and-reflect-ing-on-whats-possible-too/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2011/02/learning-go-and-reflect-ing-on-whats-possible-too/</feedburner:origLink></item>
		<item>
		<title>Learning Go (and serializing objects with it, too)</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/EgCshhxgziQ/</link>
		<comments>http://www.jmcneil.net/2011/02/learning-go-and-serializing-objects-with-it-too/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 20:59:02 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=281</guid>
		<description><![CDATA[I had intended to make my next target the Go RPC services, simply because RPC is cool. Nothing makes me happier than pressing a button on machine A while watching the LED on machine B flash. Nothing. As I got into the RPC code, I realized that underlying data serialization was handled by the gob [...]]]></description>
			<content:encoded><![CDATA[<p>I had intended to make my next target the Go RPC services, simply because RPC is cool. Nothing makes me happier than pressing a button on machine A while watching the LED on machine B flash. Nothing.</p>
<p>As I got into the RPC code, I realized that underlying data serialization was handled by the gob module. The gob module appears to be analogous Python&#8217;s pickle approach.  Given that, it seems that the gob foundation ought to exist before I spend any amount of time on understanding the RPC mechanism.  So, that&#8217;s what this post is about. We&#8217;ll put together a module that serializes structure data. Of course, we&#8217;ll also provide reader functionality in order to close the loop.</p>
<p>Since we&#8217;re getting a little fancier (two files this time), the little gogogo test script won&#8217;t work here. Instead, we&#8217;ll have to do it the old fashioned way.  I promise we&#8217;ll just add a Makefile if we add a third file. That&#8217;s probably worth a post itself.</p>
<h1>The gob Package</h1>
<p>The documentation for the package can be found on the <a href="http://golang.org/pkg/gob/">Go Language site</a>. Based on those pages, it&#8217;s a rather flexible system.  Instead of terminating or triggering an error condition in many cases, Go will make an effort to follow pointers and do other creative things such as leave out elements if they&#8217;re not present in the type we&#8217;re attempting to reconstruct.  This is probably something to take note of as it could be slightly surprising if it is not a behavior you&#8217;re ready for.</p>
<p>The documentation on the encoding format is quite complete and it covers things such as integer encoding, structure formatting, and the handling of signed values.</p>
<h1>Manipulating Gob Data</h1>
<p>Our example application isn&#8217;t terribly complex.  It is composed of two files. The first file, goopy.go, contains all of the code necessary for handling the serialization.  The second file, main.go, acts as the driver and provides an interface to the user.  Here&#8217;s  quick run down of the application flow.</p>
<ol>
<li>Startup and flag processing. Default to read.</li>
<li>If reading, load the gob file from disk and display it to the screen. We take care to handle missing files gracefully.</li>
<li>If writing, we encode the data in question and stream it to disk.</li>
<li>Application terminates, ensuring all files are closed.</li>
</ol>
<h2>The Stuff at the Top of the goopy.go File</h2>
<p>This isn&#8217;t overly interesting.  We just include package dependencies and define a structure type that we&#8217;ll use for serialization.</p>
<pre>
<div id="_mcePaste">
package goopy

import "gob"
import "os"

type PersonInfo struct {
  Name string
  Age int
}</div>
</pre>
<h2>Serialization</h2>
<p>The following method handles the serialization of data to a local file. The function accepts a pointer to a PersonInfo as its receiver and a path for the target data file.  We&#8217;ll return something implementing the os.Error interface if we run into a problem. Otherwise, the return value is nil.</p>
<pre>func (p *PersonInfo)SerializePersonInfoToGob(to_file string) (os.Error) {
  /* Open file and check for error state */
  file_handle, err := os.Open(to_file, os.O_WRONLY|os.O_CREAT, 0600)
  if err != nil {
    return err
  }

  /* Automatically close when we finish in this function, consider
   * with open(to_string) as file_handle. */
  defer file_handle.Close()

  /* Serialize data out. */
  gob.NewEncoder(file_handle).Encode(p)
  return nil
}</pre>
<p>Let&#8217;s step through this. It&#8217;s not overly confusing, but there are a couple of concepts covered here.</p>
<ol>
<li>The first line opens the target file. Notice the similarities between the flags here and the flags available to the standard open(2) system call. This function returns two values. An *os.File, and a possible error condition.</li>
<li>We check the error condition. If it&#8217;s non-nil, we just return it.</li>
<li>Next, since the file was opened, we call &#8216;defer file_handle.Close().&#8217; What&#8217;s this do? When a method exits, for any reason, anything that has been marked with the defer keyword will execute. This ensures that our file is closed.  If you&#8217;re familiar with Python, think &#8220;leaving a with statement.&#8221;</li>
<li>Next, we create an anonymous encoder and call the Encode method. We pass file_handle. Note that NewEncoder function expects something implementing the io.Writer interface. That is, anything with a Write method. Calling Encode flushes the serialized data down.</li>
</ol>
<p>That&#8217;s it. We then return nil to signify a successful encoding.</p>
<h2>Deserialization</h2>
<p>Deserialization is a lot like the serialization process.  Here&#8217;s the code that does that for us.</p>
<pre>func NewPersonInfoFromGob(from_file string) (*PersonInfo, os.Error) {
  file_handle, err := os.Open(from_file, os.O_RDONLY, 0600)
  if err != nil {
    return nil, err
  }
  defer file_handle.Close()
  var person PersonInfo

  decoder := gob.NewDecoder(file_handle)
  err = decoder.Decode(&amp;person)
  return &amp;person, err
}</pre>
<p>Everything should look quite familiar. Note that we now follow the &#8220;value, error&#8221; idiom here as well. This is obvious as the returned elements are a pointer to a PersonInfo and something implementing os.Error. The other thing to notice is that we pass a pointer to our PersonInfo variable to the Decode method. This ensures pass-by-reference. Our structure will be populated by the deserialization routine.</p>
<h2>Creating New Objects</h2>
<p>We add one little helper function to create new PersonInfo objects.</p>
<pre>func NewPersonInfo(name string, age int) (*PersonInfo){
  return &amp;PersonInfo{Name: name, Age: age}
}</pre>
<h2>The main.go File</h2>
<p>Now, we put together our driver code that handles user options.  Let&#8217;s look at this as one big listing and step through the interesting points.</p>
<pre>package main

import "log"
import "flag"
import "./goopy"

/* File we read and write from. This is required in any case. */
var gobfile *string = flag.String(
  "gobfile", "data.gob", "A Go Pickle of a Different Flavor.")

/* Read mode? We default to this in order to be non-destructive.
 * we'll pull Gob data out and just dump it to the screen.
 */
var writing *bool = flag.Bool(
  "writing", false, "If specified, we write the command line data.")

/* Required only in writing scenario */
var age *int = flag.Int("age", -1, "Age for person record.")
var name *string = flag.String("name", "", "Name for person record.")

func main() {
  defer func() {
    if err := recover(); err != nil {
       log.Println("Fatal Error Encountered: ", err)
    }
  }()

  flag.Parse()

  if *writing {
    person_info := goopy.NewPersonInfo(*name, *age)
    person_info.SerializePersonInfoToGob(*gobfile)
    log.Println("Serialization Complete")

  } else {

    person_info,err := goopy.NewPersonInfoFromGob(*gobfile)
    if err != nil {
      panic(err)
    }

    log.Printf("Read Complete (Dump): %+v", person_info)
 }
}</pre>
<p>Most of this should look familiar if you&#8217;ve followed my other posts to date. There are a few newer concepts (to me, as well!) here, so again, let&#8217;s walk through.</p>
<ol>
<li>Required imports and package name. Notice the &#8220;./goopy&#8221; syntax used. This is because our goopy module is located in the current directory and not in a centralized library location.</li>
<li>Next up, we setup four command line flags. The file to perform IO on, whether we want to write, and then the values for our PersonInfo structure.</li>
<li>Now, look at the first couple of lines of our main function. Different, no? Here, we defer an anonymous function that calls recover(). If you look back at our deserialization routine, you&#8217;ll notice that we&#8217;ve called panic.  Panic causes the stack to unwind and the application to exit.  If, along the way, a recover call is executed, the error passed to panic is returned and control resumes at that function return.  Note that since the stack is unwinding, the only valid place (I believe) to stick a recover call is in a deferred function.  In this case, we just use it to print our error condition and exit.</li>
<li>We then parse the flags as we&#8217;ve done before.</li>
<li>If we&#8217;re writing, we call goopy.NewPersonInfo and then proceed to serialize that information.</li>
<li>Otherwise, we default to reading our data out of file and displaying it to the screen.</li>
</ol>
<p>That&#8217;s fundamentally it in terms of our application. Notice that we&#8217;re using the log.Printf and log.Println functions here. That&#8217;s nice as it causes data printed to standard output to be prefixed with the date and time.</p>
<h2>Compiling and Running</h2>
<p>While this isn&#8217;t as straightforward as our previous tests were, it&#8217;s not difficult. First we&#8217;ll compile our application, link it, and display the command line options.</p>
<pre>mcjeff@martian:~/my_go$ 6g goopy.go
mcjeff@martian:~/my_go$ 6g main.go
mcjeff@martian:~/my_go$ 6l -o gobber main.6
mcjeff@martian:~/my_go$ ./gobber --help
flag provided but not defined: -help
Usage of ./gobber:
  -writing=false: If specified, we write the command line data.
  -name="": Name for person record.
  -gobfile="data.gob": A Go Pickle of a Different Flavor.
  -age=-1: Age for person record.</pre>
<p>First, if we run our application without a valid file, we&#8217;ll see our error handling in action.</p>
<pre>mcjeff@martian:~/my_go$ ./gobber -gobfile=/no/such/file
2011/02/17 15:43:19 Fatal Error Encountered:  open /no/such/file: no such file or directory</pre>
<p>Now, let&#8217;s run it again with the proper command line arguments needed to write new gob data out.</p>
<pre>mcjeff@martian:~/my_go$ ./gobber -writing=true -name=jeff.gob -age=31 -gobfile=jeff.gob
2011/02/17 15:45:12 Serialization Complete
mcjeff@martian:~/my_go$ ls -l jeff.gob
-rw------- 1 mcjeff mcjeff 58 Feb 17 15:45 jeff.gob</pre>
<p>Beautiful! It ran as it should, we created the file, and populated it with our command line data.  Finally, let&#8217;s run our new utility one more time in order to read the data from disk and ensure it prints the proper contents.</p>
<pre>mcjeff@martian:~/my_go$ ./gobber -gobfile=jeff.gob
2011/02/17 15:46:51 Read Complete (Dump): &amp;{Name:jeff.gob Age:31}</pre>
<p>That&#8217;s all there is to it!</p>

<p><a href="http://feedads.g.doubleclick.net/~a/TA7myObxA62ON8-G5APy6iOi8oY/0/da"><img src="http://feedads.g.doubleclick.net/~a/TA7myObxA62ON8-G5APy6iOi8oY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/TA7myObxA62ON8-G5APy6iOi8oY/1/da"><img src="http://feedads.g.doubleclick.net/~a/TA7myObxA62ON8-G5APy6iOi8oY/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/EgCshhxgziQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2011/02/learning-go-and-serializing-objects-with-it-too/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2011/02/learning-go-and-serializing-objects-with-it-too/</feedburner:origLink></item>
		<item>
		<title>Learning Go (and integrating with inotify, too)</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/TU6RS3dUY0g/</link>
		<comments>http://www.jmcneil.net/2011/02/learning-go-and-integrating-with-inotify-too/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 04:58:20 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=273</guid>
		<description><![CDATA[Go provides a native interface into the Linux inotify system. What&#8217;s inotify?  According to the man page, the inotify API provides a mechanism for monitoring file system events.  It can be used to monitor individual files, or directories.  There are a series of system calls available providing access to inotify. Here&#8217;s a quick run down of what [...]]]></description>
			<content:encoded><![CDATA[<p>Go provides a native interface into the Linux inotify system. What&#8217;s inotify?  According to the man page, the inotify API provides a mechanism for monitoring file system events.  It can be used to monitor individual files, or directories.  There are a series of system calls available providing access to inotify. Here&#8217;s a quick run down of what they are and what they do.</p>
<ul>
<li><strong>inotify_init</strong> &#8211; Creates an instance and returns a file descriptor referring to that instance.</li>
<li><strong>inotify_add_watch</strong> &#8211; Updates the watch list associated with an inotify instance.  Based on its arguments, it configures the instance to let us know when certain events happen.</li>
<li><strong>inotify_rm_watch</strong> &#8211; The inverse of inotify_add_watch.</li>
<li><strong>read</strong> &#8211; Wait, read? Yeah. The application read()&#8217;s on the inotify file descriptor, which blocks until events occur. File descriptors can be monitored with the standard set of primitives &#8212; poll, select, et al.</li>
<li><strong>close</strong> &#8211; Calling close on an inotify file descriptor destroys the instance.</li>
</ul>
<p>All in all, it&#8217;s a fairly straightforward API.  Watches are configured with bitmasks and events are reported by feeding event structures to the read file descriptor.  For more information, see the <a href="http://en.wikipedia.org/wiki/Inotify">Wikipedia page</a>.</p>
<p>Where is it used? Well,  consider desktop indexing applications. For a lower level reference, the udevd system monitors udev rules via inotify and automatically reloads them when changes are detected.</p>
<h1>Our Example Application</h1>
<p>We&#8217;re not going to write anything as fancy as udevd, or as useful as a desktop indexing daemon.  Instead, we&#8217;ll put together a simple Go application that uses inotify integration and a collection of channels to calculate the size of files written to a directory. Nothing fancy.</p>
<h2>What we Stick at the Top of the File</h2>
<p>First thing&#8217;s first. We simply name our package and import others that we depend on.</p>
<pre>
<div id="_mcePaste">package main

import ("flag"
        "fmt"
        "os"
        "os/inotify"
)

var watch_target *string = flag.String("watch", ".", "The directory to keep an eye on")</div>
</pre>
<p>The only other thing going on here worthy of mention is the flag.String line. Since we want our tremendously useful application to be configurable, we&#8217;re using the flag module to set up a string flag.  This line sets up command line argument processing. The watch_target variable will contain the argument value as set by &#8216;&#8211;watch&#8217;, or the default, once control is passed to main(). The Go runtime will also automatically setup the &#8220;&#8211;help&#8221; flag as well, which will print the help strings for all arguments defined. Neat.</p>
<h2>Our Changed File Structure</h2>
<p>When we fire up our application, we want to read change events, pass them to a goroutine, and then simply forget about it.  When we pass the changes off, we need to tell our system which file changed as well as what to do with our result output.  We define the following structure.</p>
<pre>type ChangedFile struct {
  output_channel chan string
  filename string
}</pre>
<p>This simply contains two elements. An output channel that we&#8217;ll stream our results to and the filename of the changed entity.</p>
<h2>Reporting Output</h2>
<p>Next, we define a function that handles printing output to the screen. We run this in it&#8217;s own goroutine to keep concurrent routines from stepping on each other.</p>
<pre>func notificationReporter(input chan string) {
  for {
    queue_data := &lt;-input
    if len(queue_data) == 0 {
      return
    }
    fmt.Println("Change Received: ", queue_data)
  }
}</pre>
<p>This is fairly straightforward. We pass in the channel in which we&#8217;ll read our input from. Next, we enter into an infinite loop. We just print the data to standard out.  However, if we get a zero-length string, we terminate the routine.  Though this isn&#8217;t really going to happen in our little example as we&#8217;re not rigging up sentinel values. We just quit on a Control+C.</p>
<h2>The Change Processor</h2>
<p>Next, we put together the method that handles processing of each individual change. It&#8217;s a method because it has a specific receiver, without it, we&#8217;d call it a function.  Here we stat the file changed, build a log string, and send that value to the channel attribute of the receiver.</p>
<pre>func (c *ChangedFile)ProcessChange() {
  statbuf, _ := os.Stat(c.filename)
  c.output_channel &lt;- fmt.Sprintf("%s is %d bytes", c.filename, statbuf.Size)
}</pre>
<p>As you may have guessed by now, c.output_channel is the other end of the channel that we read from in the above notificationReporter function.  We&#8217;ll wire it all up in our main driver method.</p>
<h2>The Main Method</h2>
<p>Let&#8217;s just take a look at this one and then step through it afterwards.</p>
<pre>func main() {
  flag.Parse()
  var report_channel = make(chan string, 5)
  go notificationReporter(report_channel)
  watcher, _ := inotify.NewWatcher()
  watcher.AddWatch(*watch_target, inotify.IN_CLOSE_WRITE)
  for {
    select {
      case event := &lt;-watcher.Event:
        change := &amp;ChangedFile{report_channel, event.Name}
        go change.ProcessChange()
      case error := &lt;-watcher.Error:
        panic(error)
    }
  }
}</pre>
<p>First off, we create a channel named report_channel, with a buffer of 5. This allows us to queue up to 5 results for writing before the enqueuing would block on a full &#8220;pipe.&#8221; Next, we fire off the notificationReporter function defined above. By using the go keyword, we allow it to run concurrently with our main line of control.</p>
<p>Next up, our inotify.Watcher is created. We then &#8220;load&#8221; the watcher with an event.  This takes two arguments &#8211; the directory we want to watch and the events we care about.  In this example, we just care about file close events for files that were written.</p>
<p>The for loop is slightly interesting.  Here you&#8217;ll see a Go select block. The select system is much like a switch statement, however, the individual cases are channels or IO endpoints.  If the tested object is ready to perform IO, then the following block will execute.  A default block could also be created, which would fire if none of the specific cases match. Finally, the select group will block until it is explicitly exited.</p>
<p>Within this loop, we create a new ChangedFile and configure it with our reporting channel and the name of the file that has been modified. We then execute change.ProcessChange by using the go keyword again, which causes it to run concurrently with the main line of control and the reporting function. We now have three concurrent paths executing at the same time.</p>
<p>Lastly, we just panic on error instead of building proper error handling in.</p>
<h2>The Output</h2>
<p>Alright, we&#8217;ll first run our code using the little build script we stuck in our ~/.profile file in the <a href="http://www.jmcneil.net/2011/02/learning-go-and-reading-tar-files-with-it-too/">first Go blog entry</a>.</p>
<pre>[jeff@martian ~]$ gogogo test.go</pre>
<p>There&#8217;s not a whole lot going on there. If everything works correctly, the code will compile and execute. From there, it will just block waiting for directory change events.  In another window, we&#8217;ll write a few files.</p>
<pre>[jeff@martian ~]$ touch a b c d e; echo "bytes" &gt; f</pre>
<p>Alright, now if we switch back to the other window, we&#8217;ll see something interesting.</p>
<pre>Change Received:  ./a is 0 bytes
Change Received:  ./b is 0 bytes
Change Received:  ./c is 0 bytes
Change Received:  ./d is 0 bytes
Change Received:  ./e is 0 bytes
Change Received:  ./f is 6 bytes</pre>
<p>Well, that&#8217;s it. As each file is written and closed, our events are handled as outlined above.  When the fun is over, simply terminate the Go application with a Control+C.  As I learn a bit more about Go, I&#8217;ll get to closing down channels properly and cover that in a later post. Additionally, we didn&#8217;t close down our inotify handle correctly, either.  We rely on the operating system to handle all of that for us when the process terminates.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/LjdXuhGdJ3ndvv_N8Fb9HcE2wIE/0/da"><img src="http://feedads.g.doubleclick.net/~a/LjdXuhGdJ3ndvv_N8Fb9HcE2wIE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/LjdXuhGdJ3ndvv_N8Fb9HcE2wIE/1/da"><img src="http://feedads.g.doubleclick.net/~a/LjdXuhGdJ3ndvv_N8Fb9HcE2wIE/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/TU6RS3dUY0g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2011/02/learning-go-and-integrating-with-inotify-too/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2011/02/learning-go-and-integrating-with-inotify-too/</feedburner:origLink></item>
		<item>
		<title>Learning Go (and hitting C libraries with it, too)</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/9-D1mOOKSC0/</link>
		<comments>http://www.jmcneil.net/2011/02/learning-go-and-hitting-c-libraries-with-it-too/#comments</comments>
		<pubDate>Tue, 15 Feb 2011 19:50:05 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[Go]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=238</guid>
		<description><![CDATA[Update: This is already underway in a real fashion. Check out go-python for more information. Looks like a solid project! Being the type of guy that doesn&#8217;t like to learn anything at the surface level, I decided to look into how one would integrate an existing C library with a Go application. My curiosity was [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update: </strong>This is already underway in a real fashion. Check out g<a href="https://bitbucket.org/binet/go-python">o-python</a> for more information. Looks like a solid project!</p>
<p>Being the type of guy that doesn&#8217;t like to learn anything at the surface level, I decided to look into how one would integrate an existing C library with a Go application. My curiosity was two fold. First, I hoped to learn a bit more about what lives under the Go-hood.  Secondly, being a new language, my assumption is that there are a lot of native libraries that haven&#8217;t yet been wrapped.</p>
<p>I spent a while trying to hunt down a simple, step-by-step guide that would lay out all of the steps needed to do this.  Python has <a href="http://docs.python.org/extending/index.html">excellent documentation</a> when it comes to handing extending and embedding. I was hoping that I&#8217;d come across such a document written from a Go perspective, but I wasn&#8217;t able to find one.  Using examples and tool documentation, however, I was able to get some test code put together. Below you&#8217;ll find a rundown of what I did and how I did it.</p>
<p>My goal was to link in Python and execute Python code from within a Go executable. I wouldn&#8217;t recommend ever doing this for any reason, ever. Actually, you may want to just stop reading now.</p>
<h2>Using the cgo Compiler</h2>
<p><span style="font-size: 13px; font-weight: normal;">When building Go code that needs to interface with an existing C library, you&#8217;ll compile using the cgo compiler instead of the usual ${num}g.  So, the approach I took was to isolate all of that code into a specific library and then access those functions as I would any other package. </span></p>
<h2>The &#8220;C&#8221; Package</h2>
<p>Generally speaking, C provides a flat, non-hierarchical namespace. Protection is limited to source file scope and is dictated by the programmer&#8217;s use of the static keyword. Simply put, everything is visible everywhere unless declared static. This is why C API definitions usually start with an identifying prefix. For Python developers, consider the Py_ prefix. It provides a way to create independent namespaces (though, with no protection between them).<br />
When interfacing with C libraries, Go wraps everything C under the &#8220;C&#8221; package.  For example, printf as defined in stdio.h becomes C.printf. This provides a nice demarcation between the Go world and the everything else world.</p>
<h2>Including Headers</h2>
<p>So, now we know what we&#8217;ll use to build the code and how we&#8217;ll interface with it.  The next step is to ensure Go knows where it can find the necessary headers.  To do this, we embed the information in comments immediately preceding the import &#8220;C&#8221; line.</p>
<pre>
<div id="_mcePaste">// #include &lt;Python.h&gt;
import "C"</div>
</pre>
<p>This ensures that the definitions in Python.h are visible to cgo. Everything found here will be made available under the C namespace and is accessible to code within this source module.  Now, as an aside, I noticed that C preprocessor macros were not expanded. So, because PyRun_SimpleString is simply a macro that calls PyRun_SimpleStringFlags, I had to use the latter.</p>
<h2>The Makefile</h2>
<p>We&#8217;ll be using the following makefile.  This comes from the example code under <em>$GOROOT/misc/cgo/gmp</em>.</p>
<pre># Copyright 2009 The Go Authors.  All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

include ${GOROOT}/src/Make.inc

TARG=pygo

# Can have plain GOFILES too, but this example doesn't.

CGOFILES=\
  pygo.go

CGO_LDFLAGS=-lpython2.6
CGO_CFLAGS = -I/usr/include/python2.6

# To add flags necessary for locating the library or its include files,
# set CGO_CFLAGS or CGO_LDFLAGS.  For example, to use an
# alternate installation of the library:
# CGO_CFLAGS=-I/home/rsc/gmp32/include
# CGO_LDFLAGS+=-L/home/rsc/gmp32/lib
# Note the += on the second line.

CLEANFILES+=pygo

include ${GOROOT}/src/Make.pkg

# Simple test programs
pygo:
  $(GC) pygo.go
  $(LD) -o $@ pygo.$O</pre>
<p>There&#8217;s a not very much going on here. If you compare this file to the example, we&#8217;re simply changing a few internal variables.</p>
<ul>
<li>TARG is the name of the library we&#8217;ll be building.</li>
<li>CGO_LDFLAGS &amp; CGO_CFLAGS are generally the same as LDFLAGS &amp; CFLAGS. They&#8217;ll be passed on during the compilation and linking phases.</li>
<li>CLEANFILES is pretty self-explainatory.</li>
</ul>
<p>Finally, we add the pygo rule at the bottom and remove the example rules for gmp.</p>
<h2>The pygo Package</h2>
<p>Now that we have our Makefile setup and ready to go, we need to put together our actual Go package. Below you&#8217;ll find the listing as I used it. Note that in a few places I purposefully used the long way as a learning tool.</p>
<pre>package pygo

/* "C" isn't a real package. Rather, it's a virtual one created when building
 * via cgo. Cgo, as opposed go 6g, allows us to access C code/libraries from
 * within a Go application. Everything in the C-world is then jammed under the
 * 'C.' namespace.
 */

// #include &lt;Python.h&gt;
// #include &lt;pythonrun.h&gt;
import "C"

/* Some basic file IO helpers live here. */
import "io/ioutil"

/* Create a PythonCode object, which is a struct, containing
 * just one field. There's no reason this couldn't have
 * just been a type PythonCode string. When I started,
 * my intention was to be a bit more complicated and store
 * return values and interpreter state and all that, but
 * there's really no point.
 */
type PythonCode struct {
  code string
}

/* In this case, a pointer to a PythonCode object is the receiver,
 * our function is called ExecPy, and there is no return value.
 * we call our internally defined init/exec/term functions.
 *
 * Two things to note here:
 * 1. i/e/t are lower case, which means that they are the equivilent
 *    of a C top level 'static void F().' Not visible outside of
 *    the package (Encapsulation FTW!).
 *
 * 2. This is a METHOD because it has a defined receiver.
 */
func (p *PythonCode) ExecPy(result chan int) {
  initPython("PYTHON_EXEC")
  py_response := execPython(p.code)
  termPython()
  result &lt;- py_response
}

/* This is our init method. There is no __init__ or __del__
 * equiv.  This builds a new object and returns a pointer to it.
 * Note that here, it's 100% okay that we're returning what
 * appears to be a pointer to a local variable. I know,
 * makes me feel a bit uncomfortable, but the docs clear
 * that up.
 */
func NewPythonCode(src *string) *PythonCode {
  contents, _ := ioutil.ReadFile(*src)
  return &amp;PythonCode{code: string(contents)}
}

/* Here we tickle the Python C API. We set the program name,
 * initialize state, and ensure we init correctly.
 */
func initPython(interp_name string) {
  C.Py_SetProgramName(C.CString(interp_name))
  C.Py_Initialize()
  if C.Py_IsInitialized() == 0 {
    panic("Could not init interp.")
  }
}

/* This executes the code. This probably could also be a method on
 * our structure-based type above, but I wanted to highlight
 * the differences between a Go method and a Go function.
 */
func execPython(python_code string) int {
  return int(C.PyRun_SimpleStringFlags(C.CString(python_code), nil))

}

/* Fall Py_Finalize and free up interp. data structures. Again,
 * this probably would work better using an interpreter Go
 * object and then a method to pass in code to exec, but this
 * covers more ground
 */
func termPython() {
  C.Py_Finalize()
}</pre>
<p>There&#8217;s quite a bit going on in there, so let&#8217;s step through it in a bit more detail.</p>
<ol>
<li>The first few lines are straight forward. We name our package pygo, include the correct C headers, and import io/ioutil.</li>
<li>Next, we create a PythonCode type, which is struct. This object simply contains a string which will be actual Python code.  As the comment states, we could have done this simpler, but I think the struct approach is probably more representative of idiomatic Go (correct me, someone?).</li>
<li>Next, we define ExecPy. Since it has a capital &#8216;E&#8217;, it is exported from the package and available elsewhere.  This method does three things, all by calling other functions internal to the package.  Notice that it takes a channel of int objects as its sole parameter. We pass the return value of execPython back up the channel instead of simply returning it.  In the real world, a return value would be simpler, however, this illustrates the usage of channels.</li>
<li>After that, we have NewPythonCode. As Go doesn&#8217;t provide initializers/constructors, we simply do the build in an appropriately named factory function like this.  Here, you see the calls directly into the Python library. In this case, C.Py_SetProgramName, C.Py_Initialize, and C.Py_IsInitialized. In actuality, Go is simply calling Py_Initialize, Py_SetProgramName, and Py_IsInitialized. The other thing to note here is the use of C.CString(). This converts a Go string object into a C char *.</li>
<li>Next up is execPython. Here, we actually return the int value from C.PyRun_SimpleStringFlags. The int call/cast is necessary as a C int is not the same as a go int. Again, you&#8217;ll see the call to C.CString converting from string to char *.</li>
<li>Finally, we simply call Py_Finalize from within termPython.</li>
</ol>
<p>Pretty simple if you ask me.  I&#8217;m becoming a fan of the &#8220;C.$identifer&#8221; approach as it allows code authors to avoid having to write stub modules in C. (SWIG Status, anyone?).</p>
<h2>The Driver</h2>
<p>The driver is pure Go. There&#8217;s no C code whatsoever. We simply import our new module and call it as we would any other Go library.</p>
<pre>/* Everything goes into a package. */
package main

/* Could import individually, but this is cleaner. Sort of like wrapping Python
 * imports in order to group them on multiple lines.
 */
import ("pygo"
  "flag"
  "fmt"
  "stdio"
)

/* Flag Parsing. This is silly easy. */
var pythonSource = flag.String("pysource", "test.py", "Python Source File")

/* Main entry point. Just like C/C++ */
func main() {
  flag.Parse()

  /* Print a goofy little header so we can visualize the Go exec
   * vs. the Python exec.
   */
  fmt.Printf("Exec Python: %s\n", *pythonSource)
  fmt.Printf("-----------------------------\n\n")
  stdio.Stdout.Flush()

  /* Create a channel, which is like a queue. We'll block on
   * this for our Pythoning to finish.
   */
  ch := make(chan int)

  /* Create, set code, Exec Py. But.. do it in a different thread
   * of control! All we did was fire it after the keyword "go."
   * Sweet.
   */
  go pygo.NewPythonCode(pythonSource).ExecPy(ch)

  /* This says "fill python_result with whatever comes out
         * of the channel." This is a blocking call.
   */
  python_result := &lt;-ch
  fmt.Printf("\n\n-----------------------------\n")

  /* Another way of printing... */
  fmt.Println("Channel Returned Code: ", python_result)
}</pre>
<p>That&#8217;s all there is to it. Again, let&#8217;s walk through this source listing.</p>
<ol>
<li>We name our package and import our dependencies. Note that our new package appears here and it is listed like any other package.</li>
<li>Next we setup a &#8211;pysource flag, so we can specify a Python file on the command line. This lets us run arbitrary Python code from our Go executable.</li>
<li>We print a header and flush standard output. This is to ensure Go finishes printing (buffered?) before Python starts running.</li>
<li>Next, we create a channel of integers. The channel is used to send the result of our Python execution back to our driver code. Note the use of the make function versus the new function here.</li>
<li>The next line passes the location of the Python source file to a new PythonCode object (that we created via NewPythonCode). See how this call is prefixed with the &#8220;go&#8221; keyword? This allows the Go runtime to run both the driver code as well as the Python system concurrently.</li>
<li>Finally, we wait on our channel and print the exit code.  If we didn&#8217;t wait, the driver would complete execution before our Python library ran. In short, much like terminating the main thread before a worker thread has a chance to complete.</li>
</ol>
<h2>The Test Code</h2>
<p>The following snippet of Python code is what I used to test. The metaclassery is not needed, but I was curious as to whether it would cause any issues (I didn&#8217;t think it would!).</p>
<pre>import sys

class GoofyMeta(type):
  def __new__(*args, **kw):
    print "In Go-&gt;Python Metaclass"
    return type.__new__(*args, **kw)

class HelloFromGo(object):
  __metaclass__ = GoofyMeta
  def __str__(self):
    return "Hi, you are running Go."

if __name__ == '__main__':
  h = HelloFromGo()
  print h

  print "See, not kidding: "
  print sys.version

  print "Here's my global namespace: "
  print dir()</pre>
<p>So, as a control, let&#8217;s run the Python code from the command line first, to ensure it runs as we think it should.</p>
<pre>mcjeff@martian:~/pygo$ python test.py
In Go-&gt;Python Metaclass
Hi, you are running Go.
See, not kidding:
2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3]
Here's my global namespace:
['GoofyMeta', 'HelloFromGo', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'h', 'sys']
mcjeff@martian:~/pygo$</pre>
<p>Now that we&#8217;re certain everything works, we can move forward with compilation and testing.</p>
<h2>Compilation and Running</h2>
<p>For this example, I&#8217;m going to use the same little shell function I used in my <a href="http://www.jmcneil.net/2011/02/learning-go-and-reading-tar-files-with-it-too/">first Go post</a>. Everything else is new.  Let&#8217;s take a look at what&#8217;s required to build this extension.</p>
<pre>mcjeff@martian:~/pygo$ export GOROOT=~/go
mcjeff@martian:~/pygo$ make
CGOPKGPATH= cgo -- -I/usr/include/python2.6 pygo.go
6g -o _go_.6  pygo.cgo1.go _cgo_gotypes.go
6c -FVw -I"/home/mcjeff/go/pkg/linux_amd64" _cgo_defun.c
gcc -m64 -g -fPIC -O2 -o _cgo_main.o -c -I/usr/include/python2.6  _cgo_main.c
gcc -m64 -g -fPIC -O2 -o pygo.cgo2.o -c -I/usr/include/python2.6  pygo.cgo2.c
gcc -m64 -g -fPIC -O2 -o _cgo_export.o -c -I/usr/include/python2.6  _cgo_export.c
gcc -m64 -g -fPIC -O2 -o _cgo1_.o _cgo_main.o pygo.cgo2.o _cgo_export.o -lpython2.6
cgo -dynimport _cgo1_.o &gt;__cgo_import.c &amp;&amp; mv -f __cgo_import.c _cgo_import.c
6c -FVw _cgo_import.c
rm -f _obj/pygo.a
gopack grc _obj/pygo.a _go_.6  _cgo_defun.6 _cgo_import.6 pygo.cgo2.o _cgo_export.o
mcjeff@martian:~/pygo$ make install
cp _obj/pygo.a "/home/mcjeff/go/pkg/linux_amd64/pygo.a"
mcjeff@martian:~/pygo$</pre>
<p>That&#8217;s it. The files included in our Makefile handle the setup and compilation for us. There are a series of intermediary files created that we really don&#8217;t have to concern ourselves with.  If you&#8217;re curious, they&#8217;re left around by the compiler. A simple &#8216;ls&#8217; will display them.</p>
<p>Finally, we can run our Go binary and execute our small Python example.</p>
<pre>mcjeff@martian:~/pygo$ source ~/.profile
mcjeff@martian:~/pygo$ gogogo main.go
Exec Python: test.py
-----------------------------

In Go-&gt;Python Metaclass
Hi, you are running Go.
See, not kidding:
2.6.5 (r265:79063, Apr 16 2010, 14:15:55)
[GCC 4.4.3]
Here's my global namespace:
['GoofyMeta', 'HelloFromGo', '__builtins__', '__doc__', '__name__', '__package__', 'h', 'sys']

-----------------------------
Channel Returned Code:  0
mcjeff@martian:~/pygo$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped</pre>
<p>Well, there you have it. A quick run down on how to access C libraries from a Go application.  I find it rather elegant, honestly. Now, as for the embedded Python?  I wouldn&#8217;t use this anywhere, ever, for any reason. I&#8217;ve no idea what&#8217;s going on with regards to internal thread states and structures. This is nice little example, but probably not such a hot idea!</p>

<p><a href="http://feedads.g.doubleclick.net/~a/v6RmqxC8Qxw_0UB6Jtobh0xNIro/0/da"><img src="http://feedads.g.doubleclick.net/~a/v6RmqxC8Qxw_0UB6Jtobh0xNIro/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/v6RmqxC8Qxw_0UB6Jtobh0xNIro/1/da"><img src="http://feedads.g.doubleclick.net/~a/v6RmqxC8Qxw_0UB6Jtobh0xNIro/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/9-D1mOOKSC0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2011/02/learning-go-and-hitting-c-libraries-with-it-too/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2011/02/learning-go-and-hitting-c-libraries-with-it-too/</feedburner:origLink></item>
		<item>
		<title>Learning Go (and reading Tar files with it, too)</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/8OO0RK3mq_w/</link>
		<comments>http://www.jmcneil.net/2011/02/learning-go-and-reading-tar-files-with-it-too/#comments</comments>
		<pubDate>Tue, 15 Feb 2011 04:52:55 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=225</guid>
		<description><![CDATA[Over the past couple of days, I&#8217;ve taken an interest in Go. I&#8217;ve gone through the bulk of the documentation. I&#8217;ve read the tutorial, the Effective Go documentation, and a collection of other works available on the documentation page. I&#8217;m really taking quite a liking to it. Why? It&#8217;s quite expressive. This was one of the [...]]]></description>
			<content:encoded><![CDATA[<p>Over the past couple of days, I&#8217;ve taken an interest in <a href="http://www.golang.org">Go</a>. I&#8217;ve gone through the bulk of the documentation. I&#8217;ve read the tutorial, the Effective Go documentation, and a collection of other works available on the <a href="http://golang.org/doc/docs.html">documentation page</a>. I&#8217;m really taking quite a liking to it. Why?</p>
<ul>
<li>It&#8217;s quite expressive. This was one of the main things that got me into Python. I liked the fact that I could squeeze a lot of functionality out of just a few lines of well thought out code. Go provides that same functionality and it gives near-C performance (though, of course, there is overhead).</li>
<li>It&#8217;s a small language. This is why I&#8217;ve always preferred C to C++. C is a very, very small language. There isn&#8217;t much to it at all. Once one gets the idioms down, C programming is not overly difficult. Some of the OS level work might be, but the language itself is very small.</li>
<li>It&#8217;s quite easy to extend.  I actually wrapped Python in Go this afternoon after only about an hour of effort. The <em>cgo </em>compiler provides very straightforward means of integrating and linking native C code.</li>
<li>It provides a very intuitive and easy-to-use threading/parallelism model with the use of goroutines.</li>
</ul>
<p>What&#8217;s there not to like? Exactly. While the standard library has yet to read &#8220;batteries included&#8221; status, it is getting there. Now, you&#8217;ll find modules for SMTP, networking, HTTP,  and IO, among other things.  There&#8217;s even a growing collection of third party modules available on the <a href="http://godashboard.appspot.com/package">Package Dashboard</a>.</p>
<p>After reading through the available documentation, I decided to try my hand at a few examples. I couldn&#8217;t very much decide where to start, so I opened the standard library reference and started with &#8216;A.&#8217;  In this case, that means the <em>archive</em> packages &#8211; <em>tar</em> and <em>zip</em>.</p>
<h2>Reading Tar Files with Go</h2>
<p>First off, if you don&#8217;t have Go installed as of yet, head over to the <a href="http://golang.org/doc/install.html">getting started guide</a>. Installation is source driven, but it&#8217;s truly very simple.  The compilation is slightly bulky as you&#8217;ll need to compile, link, execute.  That&#8217;s a cycle I haven&#8217;t used in a while.  In order to speed it up, I&#8217;ve defined the following shell function in my .profile.</p>
<pre>
<div id="_mcePaste">gogogo() {
  source=$1
  base=$(basename $source .go)
  6g $source
  6l -o $base $base.6
  $(pwd)/$base
}</div>
</pre>
<p>Of course, this little rule only works when building one file at a time.</p>
<p>Now, let&#8217;s setup the environment.  This would work with much larger tar files, but for example purposes, we&#8217;re going to limit ourselves to some very small ones.  The test environment was setup as follows:</p>
<pre>$ echo "one" &gt; 1
$ echo "two" &gt; 2
$ echo "three" &gt; 3
$ tar -cvf test.tar ./[123]
a ./1
a ./2
a ./3
$</pre>
<p>Notice that we&#8217;ve simply created three text files, named 1, 2, and 3. Each file contains its english representation.  Let&#8217;s spice it up a bit and change the contents of &#8220;1&#8243; to один, which is simply the Russian word for &#8220;one.&#8221;</p>
<pre>$ echo 'один' &gt; 1
$ cat 1
один
$</pre>
<p>Alright. Now, let&#8217;s have a look at the Go code needed to read from the tar file we created.</p>
<pre>package main

import "archive/tar"
import "fmt"
import "os"

func main() {
  f,_ := os.Open("test.tar", os.O_RDONLY, 0600)
  reader := tar.NewReader(f)
  file_count := 1
  for hdr,err := reader.Next(); err == nil; hdr, err = reader.Next() {
    b := make([]byte, hdr.Size)
    fmt.Printf("%d: %s (%d bytes)\n", file_count, hdr.Name, hdr.Size)
    reader.Read(b)
    fmt.Println("-----&gt; ", string(b))
    file_count++
  }
}</pre>
<p>That&#8217;s all there is to it. Before we go into detail and explain exactly what&#8217;s going on here, let&#8217;s built it (using our shortcut) and run in order to verify the output.</p>
<pre>$ gogogo tar.go
1: ./1 (9 bytes)
-----&gt;  один

2: ./2 (4 bytes)
-----&gt;  two

3: ./3 (6 bytes)
-----&gt;  three</pre>
<p>As an aside, if you run an <em>ls </em>from the current directory, you&#8217;ll see the intermediate files needed by the go compiler. We&#8217;re just skipping that step with our profile function. Let&#8217;s take a closer look at the code, and then double back and review the results.</p>
<p>The very first line of the file declares that we&#8217;re defining package main. Each Go source file requires a package name. Larger applications are simply collections of linked packages. The idiomatic name for the main package is, not suprisingly, main.</p>
<p>Next we import three more packages. These are all used within the file. Note that if we were to import a package that we&#8217;re not using, the application would not compile. That ensure we always have clean code without a polluted namespace.</p>
<p>Now, we define a main function. This is the application entry point, much like you&#8217;ll see in a C, C++, or Objective-C program.</p>
<ol>
<li>We open a file by using the os.Open function. In Go, identifiers are only exported from packages if they begin with a capitol letter (think static vs. non-static C functions).  The os.Open function returns a file object.</li>
<li>Next, we create a tar reader. The NewReader function expects an object implementing the Reader interface. Note that with Go, there&#8217;s no need to declare what you&#8217;re implementing. If you add the required methods, you automagically implement the interface. I like this approach. Duck typing light, if you will.</li>
<li>We then iterate through the contents of the tar file by calling reader.Next. In Go, functions and methods can return more than one value. It&#8217;s common to see the actual value and a possible error condition passed back. As long as the error condition is not nil (Go&#8217;s None/NULL), we keep reading. The reader.Next method returns a header structure as well as an error value.</li>
<li>Now, we create a slice of bytes. The make syntax creates a slice and an underlying array. For more information, see the <a href="http://golang.org/doc/effective_go.html#allocation_make">Go documentation on arrays and slices</a>.</li>
<li>We print some status information, read the full contents of each element in the tar file, and print the results. We increment our file number counter so we can display how many files we&#8217;ve read.</li>
</ol>
<p>Just for reference purposes, the Tar header is defined as the following in archive/tar:</p>
<pre>type Header struct {
    Name     string
    Mode     int64
    Uid      int
    Gid      int
    Size     int64
    Mtime    int64
    Typeflag byte
    Linkname string
    Uname    string
    Gname    string
    Devmajor int64
    Devminor int64
    Atime    int64
    Ctime    int64
}</pre>
<p>Pretty straightforward, no?  Now, double back and look at the results from earlier. They should all make sense. Well, maybe except for our little Russian file! Note that this record says that it is 9 bytes in size, while the remaining files state that they are equal to the number of files plus the trailing newline.  The answer is pretty simple. Each Cyrillic letter takes up two bytes when UTF-8 encoded. Go transparently handles that complexity for us. So, we&#8217;re looking at four two-byte letters, followed by a standard newline.</p>
<pre>$ file 1
1: UTF-8 Unicode text
$ file 2
2: ASCII text
$</pre>
<p>So, all in all, I&#8217;m starting to like this language. Take a minute and dive into it. Now, of course, the challenge becomes finding something worthwhile to write in Go. I&#8217;ve learned a small collection of languages over the past year, only to forget most of them due to lack of use. As an interesting aside, I had been planning on refreshing my C/C++. I think I may defer that a bit and really spend some time on this language.</p>
<p><strong>Update: </strong>I&#8217;ve been asked how one woud manage a gzip compressed tar file.  Well, remember interfaces? The reader we pass into the tar.NewReader function simply has to implement the Reader interface! So, we can update the code above to open a gzip file and pass that reader in, like so:</p>
<pre>package main

import ("fmt"
        "archive/tar"
        "compress/gzip"
        "os"
       )

func main() {
  fhandle, _ := os.Open("test.tar.gz", os.O_RDONLY, 0600)
  zhandle, _ := gzip.NewReader(fhandle)
  thandle := tar.NewReader(zhandle)
  hdr, _ := thandle.Next()
  fmt.Println(hdr.Name)
}</pre>
<p>See? All we&#8217;ve done here is chain our NewReader calls, as each returned object implements the Reader interface.  Running the code provides the following output.</p>
<pre>mcjeff@macbook:~$ ls test.tar.gz
test.tar.gz
mcjeff@macbook:~$ gogogo gunzip.go
./1</pre>
<p>There. Hope that clears it up!</p>

<p><a href="http://feedads.g.doubleclick.net/~a/2lBD20-OF00ikAi6IXWhq7E20IY/0/da"><img src="http://feedads.g.doubleclick.net/~a/2lBD20-OF00ikAi6IXWhq7E20IY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/2lBD20-OF00ikAi6IXWhq7E20IY/1/da"><img src="http://feedads.g.doubleclick.net/~a/2lBD20-OF00ikAi6IXWhq7E20IY/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/8OO0RK3mq_w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2011/02/learning-go-and-reading-tar-files-with-it-too/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2011/02/learning-go-and-reading-tar-files-with-it-too/</feedburner:origLink></item>
		<item>
		<title>A Book About (Python) Books</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/mJrbB66XBRI/</link>
		<comments>http://www.jmcneil.net/2010/12/a-book-about-python-books/#comments</comments>
		<pubDate>Fri, 17 Dec 2010 03:25:02 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[books]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=200</guid>
		<description><![CDATA[It&#8217;s been quite a while since I&#8217;ve posted a message here on my blog.  With the new job, offspring, holidays, and time spent in front of a text editor, I just haven&#8217;t had a few minutes to spare. I&#8217;ve been a bit busy in the book world over the past few months, so I decided [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been quite a while since I&#8217;ve posted a message here on my blog.  With the new job, offspring, holidays, and time spent in front of a text editor, I just haven&#8217;t had a few minutes to spare. I&#8217;ve been a bit busy in the book world over the past few months, so I decided to pack it all into one blog post.</p>
<p>I&#8217;ve recently finished writing my first book, <a href="https://www.packtpub.com/python-2-6-text-processing-beginners-guide/book">Python 2.6 Text Processing Beginner&#8217;s Guide</a>. What an interesting, yet demanding experience. Did I learn a lot? You bet. Would I do it again? Maybe. It&#8217;s a large time commitment; one I&#8217;m not really interested in again anytime soon. After all, I&#8217;ve got monsters to slay and levels to attain. One can&#8217;t invest in Dwarven Shaman while being productive!</p>
<h2>The Process</h2>
<p>A long, long, long time ago, I was contacted by the Packt staff and asked if I would be willing to write a book about Python text processing. Being overly excited at the prospect of doing so, I agreed.  They did a pretty good job of ironing out the process. Here&#8217;s an outline of what one has to go through when writing a book for Packt.</p>
<ol>
<li>The outline. The first element I had to come up with was a 4-5 page summary of what I intended to cover. Being as this was a beginner&#8217;s guide to text processing, I elected categories such as XML, <a href="http://pyparsing.wikispaces.com/">PyParsing</a>, <a href="http://nucular.sourceforge.net/">Nucular</a>, and some introductory material to the Python IO system (after all, you need to read it to parse it). Working chapter titles and &#8220;example examples&#8221; were included here.</li>
<li>Initial drafts. After acceptance of my outline, the contract was finalized and it was time to crank out my first drafts.  As there were 12 chapters in the outline, I wrote 12 initial drafts. Each one took about three weeks and topped out at about 30 pages. Editor feedback trickled in as I worked through.</li>
<li>Chapter rewrites.  After finishing the first drafts, I received the chapters back. This time, they were quite marked up both by the editing staff at Packt and the technical reviewers that Packt had selected.  This is the part I enjoyed the least. The goal? Clarification, fix some wording problems, generate screen shots (I had elected fixed-width fonts initially), and address feedback. Each chapter took about a week.</li>
<li>Final Reviews. After submitting my rewrites, the chapters were then transferred to PDF format and were sent my way for final review. Each took a couple of days.  I made quite a few corrections to these. At the time of this blog post, I&#8217;m still hoping they&#8217;ve all made it in the way I wanted them!</li>
<li>Publication.  The book was officially published on December 15th. The contract is dated March 11th, 2010. That&#8217;s a lot of  busy evenings in front of the iMac.</li>
</ol>
<p>Along the way, I had to write things such as author bios, chapter summaries, introductions, sales points, and so on. I rather enjoyed the experience.   Though, I&#8217;ll be the first to admit that I was ready to be done around October.</p>
<h2>The Product</h2>
<p>I&#8217;m happy with the material covered.  I think it&#8217;s a good selection for a beginner&#8217;s guide. Not a lot of theory, but enough to clarify points when needed. My only regret? I would have loved to have gotten another round of drafts in, especially after the final review stage. But, I&#8217;m a bit of a perfectionist!</p>
<h3><a href="https://www.packtpub.com/python-2-6-text-processing-beginners-guide/book"><img class="alignleft size-full wp-image-203" title="Cover.jpg" src="http://www.jmcneil.net/wp-content/uploads/2010/12/2121OS_Cover.jpg.png" alt="Cover" width="125" height="152" /></a>Chapter Summaries</h3>
<p>Here&#8217;s a rundown of the table of contents and what was covered. This ought to paint a pretty clear picture. I made an effort to keep Python 3 in mind and even included a quick Python 2 to Python 3 upgrade example in the final appendix.</p>
<p>One of the additional goals I had was to cover some best practices while detailing methods of handling different types of textual data. For example, if we&#8217;re going to cover PyParsing in any detail, let&#8217;s go ahead and install it in a virtualenv environment.  Or, if we&#8217;re going to create some classes, let&#8217;s follow Python&#8217;s PEP8 and hopefully introduce a reader to some existing standards. The downside there? Fitting code on a printed page is quite difficult, especially when it&#8217;s more than a block or two deep. I&#8217;m not so happy with the number of spurious parenthesis or raging backslashes I had to use in order to display nicely on paper.</p>
<ol>
<li><strong>Getting Started </strong>covered introductory material such as running virtual environments and elements of text encoding (ASCII basics).</li>
<li><strong>Working with the IO System </strong>brings readers up to speed on how to interact with external sources of data. File IO, network information, and the beauty of &#8220;file like.&#8221;</li>
<li><strong>Python String Services </strong>covers what can be done using basic string methods.</li>
<li><strong>Text Processing Using the Standard Library </strong>introduces a few common standard library modules for crunching data such as CSV and JSON.</li>
<li><strong>Regular Expressions </strong>covers the Swiss Army knife.</li>
<li><strong>Structured Markup </strong>details XML via SAX, DOM, and a bit of XPath. We also visit HTML parsing via standard library routines.</li>
<li><strong>Creating Templates </strong>switches from parsing to producing. Using Mako to build and inherit text templates.</li>
<li><strong>Understanding Encodings and i18n </strong>is an introduction to character encodings, Unicode, and Unicode data encodings (UTF). I&#8217;ve always felt that these concepts are confused more than they ought to be.</li>
<li><strong>Advanced Output Formats </strong>goes over a bit of Reportlab, xlwt, and ODFPy.</li>
<li><strong>Advanced Parsing and Grammars </strong>gives a bit of background on BNF and parsing techniques and then hands the heavy work off to PyParsing, with an example on the Python NLTK.</li>
<li><strong>Searching and Indexing </strong>introduces Nucular and details how it can be helpful when searching large quantities of text data. Examples show how a linear search is much less efficient than an indexed approach.</li>
</ol>
<p>All in all, I&#8217;m happy with those topics. I&#8217;ve also tried to include a lot of community information in the appendix. Conferences, users groups, PEPs, mailing lists, and so on.</p>
<h2>While We&#8217;re Talking About Books&#8230;</h2>
<p>I had the pleasure of playing technical reviewer for Cody Precord&#8217;s<a href="https://www.packtpub.com/wxpython-2-8-application-development-cookbook/book"> </a><a href="https://www.packtpub.com/wxpython-2-8-application-development-cookbook/book">wxPython 2.8 Application Development Cookbook</a>.</p>
<p><a href="https://www.packtpub.com/wxpython-2-8-application-development-cookbook/book"><img class="size-full wp-image-218 alignright" title="1780OS_MockupCover_Cookbook_0.jpg" src="http://www.jmcneil.net/wp-content/uploads/2010/12/1780OS_MockupCover_Cookbook_0.jpg.png" alt="" width="125" height="152" /></a>This was the first experience I&#8217;ve had technically reviewing a script like this. Out of the whole process, I learned a lot about wxPython! Historically, I&#8217;ve found UI development work less than entertaining. Why? It&#8217;s always seemed slightly monotonous to me.  More than likely that&#8217;s due to an unpleasant experience with AWT during a previous lifetime.</p>
<p>Reviewing this book gave me the chance to really get in and understand the inner workings of wxPython. You know what? It&#8217;s quite easy to build a respectable looking UI! There are a collection of tips and tricks, that I wasn&#8217;t aware of, that make it an enjoyable experience.  Give it a read. Check it out. I&#8217;m quite a fan of the &#8220;cookbook&#8221; style publications.</p>
<h2>And Finally&#8230;</h2>
<p>Packt is running a discount on all Python books this December, more information is available on <a href="https://www.packtpub.com/article/exclusive-offer-on-python-books">their site</a>. No more pushing or advertising on my part. I promise.</p>
<p>I&#8217;d love to answer questions about the whole process. While at PyCon 2010, I attended a workshop manned by a collection of established Python authors. I really learned a lot there; enough to look into getting started myself. If I can return the favor or pass on a bit of knowledge, please let me know!</p>

<p><a href="http://feedads.g.doubleclick.net/~a/GcyN2zpMTvBKLexPP3Kzg4b3ecM/0/da"><img src="http://feedads.g.doubleclick.net/~a/GcyN2zpMTvBKLexPP3Kzg4b3ecM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/GcyN2zpMTvBKLexPP3Kzg4b3ecM/1/da"><img src="http://feedads.g.doubleclick.net/~a/GcyN2zpMTvBKLexPP3Kzg4b3ecM/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/mJrbB66XBRI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2010/12/a-book-about-python-books/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2010/12/a-book-about-python-books/</feedburner:origLink></item>
		<item>
		<title>Python 3: Object Oriented Programming</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/ebHthNTRMCc/</link>
		<comments>http://www.jmcneil.net/2010/09/python-3-object-oriented-programming/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 03:57:50 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[books]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=186</guid>
		<description><![CDATA[Packt has been sending me books for a bit now. Generally, I read them and post an honest review. They&#8217;ve got a track record of sending some good stuff. This time, I got a shiny new copy of Mr Dusty Phillips&#8217; Python 3 Object Oriented Programming. This was a very well written book. Quite honestly, [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #000000;">Packt has been sending me books for a bit now. Generally, I read them and post an honest review. They&#8217;ve got a track record of sending some good stuff. This time, I got a shiny new copy of Mr Dusty Phillips&#8217; </span><a href="http://www.packtpub.com/python-3-object-oriented-programming/book/mid/06081056m04f?utm_source=jmcneil.net&amp;utm_medium=bookrev&amp;utm_content=blog&amp;utm_campaign=mdb_004141"><span style="color: #000000;">Python 3 Object Oriented Programming</span></a><span style="color: #000000;">. </span></p>
<p><span style="color: #000000;">This was a very well written book. Quite honestly, I enjoyed reading it. Really. I&#8217;m not just saying that because I didn&#8217;t have to pay for my copy. In fact, this is a book I probably would have went out and bought.  This is is a wonderful addition to the shelf of any systems administrator getting into Python development. It&#8217;s also a nice &#8220;Patterns in Python&#8221; reference for the more experienced developer. But, that said, something kind of bothered me while working my way through it. I really couldn&#8217;t put my finger on it until just now. More on that later.</span></p>
<h2>Chapter Reviews</h2>
<p>Dusty did a great job of really covering a bit of everything in about 350 pages. Let&#8217;s step through the chapters and go through the plusses and minuses, according to me.</p>
<h3>Object Oriented Design</h3>
<p>I really liked the fact that this was the lead in. As the title suggestions, this book is an object oriented view of the language. This chapter presents the composition vs. inheritance argument up front, touches on multiple inheritance, and even provides an introduction to UML. Now, that said, I rarely use UML. I use it infrequently enough that I have to look up syntax rules when it comes up.  I&#8217;m not so certain this is a necessary component of the book, but it&#8217;s certainly interesting and easy to understand.</p>
<h3>Objects in Python</h3>
<p>From an experienced Python developer&#8217;s point of view, I didn&#8217;t see as much value here. That doesn&#8217;t make this a bad chapter, though. We cover things such as classes, modules, and doc strings. All of these are very, very important Python attributes and need to be understood.  I&#8217;m just not entirely certain how much the experienced folks are going to take out of this chapter.</p>
<h3>When Objects are Alike</h3>
<p>Various flavors of inheritance, MRO calculation, super, argument list formatting. This chapter falls into that same trap for the experienced developer as the second chapter did.</p>
<h3>Expecting the Unexpected</h3>
<p>Exceptions. Raising, catching, handling, recovering from, and using as a flow control technique. Hey! I like that! I use them in my own code to signal things such as terminal conditions (StopIteration, anyone?), and not-so-exceptional exceptional cases.  I like the fact that a text like this points that out.</p>
<h3>When to Use Object Oriented Programming</h3>
<p>See, I liked this chapter. We&#8217;ve all seen the standard example. This is a bike. A bike has gears. Gears can shift. While this does cover the attributes &amp; behaviors approach, it also lays an earlier foundation for things such as composition.</p>
<h3>Python Data Structures</h3>
<p>Build in data structures. I very, very rarely extend a built in object. I don&#8217;t think I&#8217;ve ever had a reason to do so. Each time I&#8217;ve tried, it&#8217;s felt like an academic exercise to see if I can correctly implement all of the __this__ and __that__ methods. Dusty goes into when it may or may not be appropriate to do so. I agree with what he has to say, I just prefer to not do that. Ever, really.</p>
<p>We also cover things like namedtuple. I love those little guys.</p>
<h3>Object Oriented Shortcuts</h3>
<p>Dunder methods and the built-ins that love them. Well, that and the comprehension collection, generators, default arguments, unpacking, functions as objects, callable objects, and a partridge in a Python tree. This chapter covers quite a bit, however it&#8217;s mostly at a superficial level. I would have liked more detail here.</p>
<h3>Python Design Patterns I &amp; II</h3>
<p>Ok, so I&#8217;m cheating on the review here a bit. These are actually two individual chapters, but they cover the same concept.  Traditional design patterns and how they relate to Python. For you OO types out there, iterator, decorator, observer, strategy, state, template, adapter, facade, lazy init, flyweight, abstract factory, and composition. Though I really think patterns are a wonderful tool of the trade, I also think it&#8217;s necessary to stress that you&#8217;re making a mistake if you look at a problem as a pattern puzzle (those are my words).  All in all, though, this book does an absolutely wonderful job of running through some of the classic design patterns and applying a Python twist to them. I enjoyed these two chapters the most.</p>
<h3>Files and Strings</h3>
<p>A good introduction. I would have liked to have seen more on the Python IO subsystem (i.e. dir(io) and explain it). More than enough to get you up and running if you&#8217;re new to the language, though. This is a pretty broad chapter. Files, to strings, to basic Unicode, to JSON, to pickle.</p>
<h3>Testing Object Oriented Programs</h3>
<p>Obligatory Testing Chapter(tm).</p>
<h3>Common Python 3 Libraries</h3>
<p>This chapter provides a survey of some commonly used Python 3 3rd party libraries and how they&#8217;re used. A very nice thing to have when dealing with a major, and incompatible, update to the language itself.</p>
<h2>Conclusion</h2>
<p>So, way back in the beginning of this post I mentioned that something bothered me about this book, but I couldn&#8217;t place it. I finally figured it out when I hit that last chapter. This book is great for someone wanting to learn Python from (close to) the beginning. In my opinion, I&#8217;d say that the Python tutorial (it&#8217;s on the Python.org site) should be a prerequisite. Then, go through this to learn a bit about Object Oriented Design using the language.</p>
<p>But, the trouble is most people that want to get into Python will still need to use the 2.x series. This is a great resources, but I&#8217;m not 100% certain the target audience is at it&#8217;s full potential yet. Why? Because the third party tool chain is still tiny as compared to 2.x. I guess, to sum the thought up, it&#8217;s an intermediate level book aimed at an audience that stands to benefit mostly from learning an earlier release.</p>
<p>Final thought. It&#8217;s worth it. While it&#8217;s a Python 3 book, the material is still 90% valid when shifted to Python 2. It&#8217;s a great way to mix some OO theory with implementation. On the bright side, you&#8217;ll pick up some Python 3 in the process. Which, of course, means you can go port some of that 3rd party tool chain.</p>
<p>On an unrelated note, Packt is now offering a subscription service to their online catalog &#8212; <a href="http://packtlib.packtpub.com/">http://packtlib.packtpub.com/</a>.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/MTzv6ftM2-YGv-GW5dheawSSv8s/0/da"><img src="http://feedads.g.doubleclick.net/~a/MTzv6ftM2-YGv-GW5dheawSSv8s/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/MTzv6ftM2-YGv-GW5dheawSSv8s/1/da"><img src="http://feedads.g.doubleclick.net/~a/MTzv6ftM2-YGv-GW5dheawSSv8s/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/ebHthNTRMCc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2010/09/python-3-object-oriented-programming/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2010/09/python-3-object-oriented-programming/</feedburner:origLink></item>
		<item>
		<title>The 2010 Open Source Awards</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/EA87fEUZLYo/</link>
		<comments>http://www.jmcneil.net/2010/08/the-2010-open-source-awards/#comments</comments>
		<pubDate>Fri, 27 Aug 2010 04:03:29 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[books]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=183</guid>
		<description><![CDATA[Packt Publishing distinguishes top OSS projects annually via their Open Source Awards.  Nominations close on September 17th, so take a minute to submit your favorite OSS project. For a bit more information, see the following link. Open Source Awards Home They&#8217;ve really turned out to be a great company to work with, so take a [...]]]></description>
			<content:encoded><![CDATA[<p>Packt Publishing distinguishes top OSS projects annually via their Open Source Awards.  Nominations close on September 17th, so take a minute to submit your favorite OSS project. For a bit more information, see the following link.</p>
<p><a href="http://www.PacktPub.com/open-source-awards-home">Open Source Awards Home</a></p>
<p>They&#8217;ve really turned out to be a great company to work with, so take a minute to check this out.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/JUfQvLDq-YWrNWQ4zoJa8C4n7Js/0/da"><img src="http://feedads.g.doubleclick.net/~a/JUfQvLDq-YWrNWQ4zoJa8C4n7Js/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/JUfQvLDq-YWrNWQ4zoJa8C4n7Js/1/da"><img src="http://feedads.g.doubleclick.net/~a/JUfQvLDq-YWrNWQ4zoJa8C4n7Js/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/EA87fEUZLYo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2010/08/the-2010-open-source-awards/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2010/08/the-2010-open-source-awards/</feedburner:origLink></item>
		<item>
		<title>Oh, I’m looking forward to this one!</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/qPYkHh2N50U/</link>
		<comments>http://www.jmcneil.net/2010/08/oh-im-looking-forward-to-this-one/#comments</comments>
		<pubDate>Sat, 07 Aug 2010 03:40:54 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[books]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=178</guid>
		<description><![CDATA[The Packt gang has asked me to review a copy of Python 3 Object Oriented Programming, and I&#8217;m really looking forward to reading this one. Really. At the day job, I still work with Python 2.x. It works wonderfully and I love it and all that, but I&#8217;d really like the opportunity to learn more [...]]]></description>
			<content:encoded><![CDATA[<p>The Packt gang has asked me to review a copy of <a title="Python 3 Object Oriented Programming" href="http://www.packtpub.com/python-3-object-oriented-programming/book/mid/06081056m04f?utm_source=jmcneil.net&amp;utm_medium=bookrev&amp;utm_content=blog&amp;utm_campaign=mdb_004141">Python 3 Object Oriented Programming</a>, and I&#8217;m really looking forward to reading this one. Really.</p>
<p>At the day job, I still work with Python 2.x. It works wonderfully and I love it and all that, but I&#8217;d really like the opportunity to learn more of the details in Python 3. Sure, I&#8217;ve read all of the release notes, checked it all out, and ran a few examples. I just haven&#8217;t actually sat down and <strong>learned </strong>it.  I&#8217;m looking forward to this.</p>
<p><img class="alignnone size-full wp-image-179" title="Python 3 Object Oriented Programming" src="http://www.jmcneil.net/wp-content/uploads/2010/08/Python-3-Object-Oriented-Programming.jpg" alt="" width="300" height="370" /></p>
<p>They&#8217;ve put a sample chapter up if you care to check it out &#8211; <a title="Chapter 7: Object Oriented Shortcuts" href="https://www.packtpub.com/sites/default/files/1261-chapter-7-Python%20object-oriented-shortcuts.pdf">Chapter 7: Object Oriented Shortcuts</a>. I&#8217;ll make sure I post a full review here once it&#8217;s arrived and I&#8217;ve had the opportunity to read it.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/EkoWW306nLQdcThFDA6a42TOMS4/0/da"><img src="http://feedads.g.doubleclick.net/~a/EkoWW306nLQdcThFDA6a42TOMS4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/EkoWW306nLQdcThFDA6a42TOMS4/1/da"><img src="http://feedads.g.doubleclick.net/~a/EkoWW306nLQdcThFDA6a42TOMS4/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/qPYkHh2N50U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2010/08/oh-im-looking-forward-to-this-one/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2010/08/oh-im-looking-forward-to-this-one/</feedburner:origLink></item>
		<item>
		<title>Week One at Google</title>
		<link>http://feedproxy.google.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~3/RTPjJf5Gwso/</link>
		<comments>http://www.jmcneil.net/2010/07/week-one-at-google/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 01:32:19 +0000</pubDate>
		<dc:creator>Jeff McNeil</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.jmcneil.net/?p=173</guid>
		<description><![CDATA[On Monday, I started my first day as a Google employee.  It was actually a bit of a hard decision as I had been at Web.com for so long.  There&#8217;s really a great group of people there and I&#8217;ll miss all of them.  They&#8217;re all great friends. Good luck, Web.com gang! Thus far, I&#8217;m really, [...]]]></description>
			<content:encoded><![CDATA[<p>On Monday, I started my first day as a Google employee.  It was actually a bit of a hard decision as I had been at Web.com for so long.  There&#8217;s really a great group of people there and I&#8217;ll miss all of them.  They&#8217;re all great friends. Good luck, Web.com gang!</p>
<p>Thus far, I&#8217;m really, really enjoying Google. It&#8217;s a breath of fresh air.  It&#8217;s possible to read up on all of the perks and whatnot on the &#8216;net, so I won&#8217;t go into that.  Above all, there&#8217;s one thing I&#8217;ve really come to like:</p>
<p>This afternoon, when I was driving home, I realized that everyone in all of the cars around me use a service that I help to produce.</p>
<p>That&#8217;s a pretty awesome feeling. I&#8217;m looking forward to spending quite a while here. I&#8217;ve learned quite a bit over the past seven days. Everything is done with the utmost quality and effort. It truly is a world class organization. Additionally, the people have been spectacular. Ready to help and share information whenever I need a bit of guidance.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/yBw_nEss82o4jtS5jDZQaOvGRv4/0/da"><img src="http://feedads.g.doubleclick.net/~a/yBw_nEss82o4jtS5jDZQaOvGRv4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/yBw_nEss82o4jtS5jDZQaOvGRv4/1/da"><img src="http://feedads.g.doubleclick.net/~a/yBw_nEss82o4jtS5jDZQaOvGRv4/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/WebInfrastructureSystemsDeploymentsAndTechnologies/~4/RTPjJf5Gwso" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.jmcneil.net/2010/07/week-one-at-google/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.jmcneil.net/2010/07/week-one-at-google/</feedburner:origLink></item>
	</channel>
</rss>

