Hacker News new | past | comments | ask | show | jobs | submit login

>I prefer Lisp's/Clojure's approach here - have many functions operating on few data types, as opposed to the inverse.

...that doesn't accurately describe a flaw in Go at all, and stems from a common misconception of Go's type system; namely that it is Java's type system, which it is decidedly not. The interfaces make a big difference.

An interface is simply a set of methods. Any object that implements those methods implements that interface. Adhering to an interface is implicit; you never have to say "type Stanley implements the Cat interface". If the Cat interface is just a "Meow" method, and Stanley can "Meow", Stanley is a Cat.

Take, for example, the io.Writer interface. io.Writer is a method set that contains a single method: the write method. This is the definition for io.Writer:

    type Writer interface {
        Write(p []byte) (n int, err error)
    }
This interface definition says "a Writer is any object that has a Write method. The Write method must accept a slice of bytes as its only argument, and it returns an integer and an error". Any object that implements this method also implements io.Writer. Therefore, any function that accepts an io.Writer may accept any object that defines this method. (when accepting io.Writer, the object's type is io.Writer; the only thing you can do with an io.Writer object inside of a method that accepts an io.Writer parameter is utilize its Write method, since that's the only thing you know it has).

So, for example, in the encoding/json package, there is an Encoder object. The Encoder object has just one method: the Encode method. This is the signature for the Encode method:

    func (enc *Encoder) Encode(v interface{}) error
this method definition reads "the function for the * Encoder type called Encode accepts an interface{} v and returns an error". interface{} is the empty interface; all objects implement at least zero methods, so any object can be supplied; it is valid to pass any object into the Encode method. The returned "error" value will let us know if something has gone wrong.

Now then. We know that we're encoding data to the json format, but to where is it being encoded? Where is the output going? The io.Encoder object embeds an io.Writer object; encoded items are written into the writer. That's a big leap. How do we know which io.Writer to write to? We inject the io.Writer when we create the encoder. This is the signature for the function that creates a json encoder:

    func NewEncoder(w io.Writer) *Encoder
It has only one argument; io.Writer. io.Writer has only one method; the Write method. That means that for any data target at all, if you define a Write method, you can encode json to it.

So what io.Writers are commonly found? There is an io.Writer for a UDP socket, a TCP socket, a websocket, an http response, a file on disk, a buffer of bytes, etc. The list goes on.

With this one Encode method, and this one Write interface, we are able to Encode json data to arbitrary targets. There's none of that JSONFileWriter, JSONHTTPResponseWriter, JSONUDPSocketStreamer stuff like you would get in other statically typed languages.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: