
Go's power is in emergent behavior - bslatkin
http://www.onebigfluke.com/2014/04/gos-power-is-in-emergent-behavior.html
======
eridius
The first example is not emergent behavior. And it has nothing at all to do
with the implicit nature of interfaces. It is in fact a pretty straightforward
consequence of the fact that functions are first-class types. Because they're
types, you can newtype them, and you can implement interfaces on the newtype.
This should work in any language that has interfaces and first-class
functions.

For reference, here's the exact same thing in Rust:

    
    
        // Define trait Foo, this is the equivalent of an interface
        pub trait Foo {
            fn foo(&self, x: int) -> int;
        }
    
        // Define a newtype called FooFunc
        pub struct FooFunc(fn(x:int) -> int);
    
        // Explicitly implement the trait on FooFunc
        impl Foo for FooFunc {
            fn foo(&self, x: int) -> int {
                let &FooFunc(f) = self; // unwrap the newtype
                f(x)
            }
        }
    
        // This is a method that uses a Foo, analogous to http.Handle()
        pub fn doFoo<T: Foo>(f: T) {
            println!("foo(42) = {}", f.foo(42));
        }
    
        // Here's our function that we want to wrap
        fn MyFoo(x: int) -> int {
            x+1
        }
    
        fn main() {
            // Call the function, just like http.Handle using http.HandlerFunc
            doFoo(FooFunc(MyFoo));
        }
    

And just like Go, this ends up being free at runtime.

~~~
md224
Yeah, it looks like their solution is just creating a function object whose
interface-required method calls the object itself (or at least that's my OOP-
centric interpretation). You could do something like that in Javascript (minus
the interface, obviously):

    
    
        var f = function(){ console.log('called'); };
        f.callMe = function(){ this(); };
    

I wonder if this is a useful pattern in JS. Can't recall ever seeing it in
practice.

~~~
NateDad
It's useful in go, because it means you can trivially turn a bare function
into a type that fulfills an interface, which makes your function more
flexible - it can easily take either a type with a method or just a method.

------
austinz
I'm not sure I understand why implicit interfaces are better than explicitly
declared interfaces. (This is an honest question.) I do iOS stuff
occasionally, and in that world one of the main purposes of interfaces (in
Objective-C, protocols) is to explicitly declare that some entity adheres to a
contract - it promises to implement some pre-agreed-upon functionality that
other entities can use. What do implicit interfaces buy you? Better static
type checking? Less typing?

/* Also, from the blog:

> Nowhere in this code did we ever declare a relationship between MyType and
> Answer.

"Answer" isn't in the example. Was this something from an earlier draft? */

~~~
latch
With implicit interfaces you're not tied to a specific interface, but rather
the method(s). If you have a type that implements Close() error, your type can
now be used anywhere (include other people's code) which accepts an io.Closer.

Add a MarshalText() (text []byte, err error) function and it can now be used
anywhere that expects a encoding.TextMarshaler.

Furthermore, your type can be used in someone's else code which has defined
its own MarshalTextCloser interface.

I believe this is what the OP means by emergent. You wrote a type that has two
methods, within your own package called "goku.Sayan", and it accidentally
satisfies the interface "picard.MarshalTextCloser" which you'll never know
about. "Sayan" was never built to satisfy _any_ interface. You just needed a
Close and MarshalText function, but none the less, "Sayan" satisfies 3
distinct interface (which could be represented by an unlimited number of
names)

I realise _accidental_ sounds dangerous, but the only real risk is that the
methods don't do what you think they should. But I don't see how that's
different from explicit interfaces; in both cases the intent is only implied
by the name. Overall, as the OP says, it's quite powerful when dealing with
simple 1 or 2 function interfaces. I think most Go developers see this
naturally emerge in their own code: they favor small interfaces specifically
for this type of re-use.

~~~
pcwalton
I think the chances that people independently developing two separate
libraries will accidentally give their methods exactly the same name, with the
same types of their arguments in the same order and with the same return
value, allowing this "emergent behavior" are very low in practice. Rather,
Close() and MarshalText() are really people implementing explicit, well-known
interfaces defined in the standard library. MarshalText() is a good example of
this—I would have named it something like Serialize() if not for the well-
known, named interface I explicitly wanted to conform to.

The primary benefit that structural interfaces give you, IMO, is less typing.
Which has plenty of value, don't get me wrong; it's awesome that Go has
successfully reduced the amount of syntactic overhead needed to implement
interfaces. But I think the benefits of it shouldn't be overstated.

~~~
seanmcdirmid
Cowboys draw their guns; artists draw their pictures; an artist cowboy draws
pictures and guns. It happens more than you think, and name hygiene is a big
deal in programming languages.

The problem goes away with less ambiguous naming conventions (e.g. DrawGun()
and DrawPicture()), but overloading is so gosh darn convenient, and thinking
of unambiguous names is quite difficult. C# is really the only mainstream
language that gets this right with explicit interface implementations.

~~~
stormbrew
I think this is more of a problem in languages that _also_ encourage having
deep class hierarchies with virtual dispatch as their main mechanism of
polymorphism. It's in those languages that you tend to see argument-less
functions like Draw() because the entire concept of what it is for that object
to be drawn as well as where has been baked in to one large composite object.

In languages that place more emphasis on type deduction and composition it's
much more likely you're calling draw to tell it what to draw on, and the
aggregate type information once you introduce an argument or two is actually
quite rich.

Which leaves you with things like Close(), which, let's be honest, we don't
need 30 interfaces that all just have Close in them just because the base
language didn't happen to include one. The concept is simple and relatively
unambiguous and almost always has to do with some kind of disposal of
resource.

~~~
seanmcdirmid
That's just how natural language is; languages based on objects will suffer
since that can't rely on full natural language power even if based on
naturalistic concepts. Any duck typed system simply doesn't care much about
name meaning at all.

------
twic
> That's it: a tiny adaptor that makes a bare function satisfy an interface.
> How is that possible?

No, why is it necessary?

In Java 8:

    
    
      public interface Handler {
          void serveHTTP(ResponseWriter w, Request r);
      }
      
      public class MyApplication {
          public static void myHandler(ResponseWriter w, Request r) {
              w.write("An even easier webserver?");
          }
      
          public static void main(String... args) {
              Http.handle("/", MyApplication::myHandler);
          }
      }
    

No adaptor needed!

Or even:

    
    
      public class MyApplication {
          public static void main(String... args) {
              Http.handle("/", (w, r) -> w.write("An even easier webserver?"));
          }
      }
    

And please bear in mind that this is Java, the slowest-moving and least
sophisticated of contemporary languages! Why does Go require so much more
boilerplate than Java?

~~~
nnutter
Do you get to use Java 8 in production?

Edit: To clarify I mean if you had a Java X app deployed how hard is it to
upgrade to Java 8? One thing I like, maybe naively, about Go is static
binaries.

~~~
lmm
It's pretty trivial. 1. Upgrade JVM on server (i.e. change 1 line of puppet
config) 2. Build with Java 8 (i.e. change target option in your build file) 3.
Deploy.

I mean sure, you have to install the new JVM, but if you don't have a system
in place for making changes to your servers then you've got bigger problems
than which language you're using. And honestly I think the JVM with its
classpath approach solves the library problem better than most platforms;
upgrading the JVM binary occasionally is no great hardship, and aside from
that everything is just jars, dynamic but not getting in the way of each other
unless you want them to. What happens when security holes are found in Go
libraries, do you have to recompile anything that depends on them?

------
pedrocr
The second one just looks like a hack. You've defined a useless function to
make an interface not implementable. It would look cleaner with a keyword in
the interface definition.

~~~
jdiez17
First of all: I agree. There are many things in Go that feel like a hack. For
example, it is common (and idiomatic) to use a map with empty values when you
want to use a set (unordered and unique values), because the map's keys are a
set. I personally dislike this, and some aspects of Go are like this.

However this blog post is about how good core language design leads to
unplanned patterns that are useful, like HandlerFunc and the private interface
hack.

~~~
Iftheshoefits
One person's "unplanned patterns that are useful" is another's "this is a
potentially dangerous hack that could lead to all manner of headaches in any
non-trivial program with even just a few hundred lines of code, let alone
thousands or millions."

~~~
politician
The sweet spot for Go is in the hundreds to a couple of thousand lines of
code. Unix philosophy and all that. Leave the monolithic MLOC monstrosities to
Java.

~~~
bsdetector
People write MLOC monstrosities in Java _because they can_. You get some
boring financial topic and some sub-par programmers and they'll write as much
garbage as the language can possibly sustain.

These things are a testament to how safe and simple Java is as a language.

Not having massive crappy code bases is a negative sign in terms of how
reliable and easy to understand a language is.

------
mjburgess
I dont know, these feel to me like very simple features ("functions are
objects", "functions take a final-type") .. nothing really "wow". The wow-
factor is, I guess, that Go can actually do it.. which seems to me a little
masochistic. ("Wow my underpowered lang. isnt so bad!").

------
coolsunglasses
There are nicer ways to do structural typing.

Here's just one example:

I have a post here of how you can partially define structure to be filled in
by the consumer of the API: [http://bitemyapp.com/posts/2014-04-11-aeson-and-
user-created...](http://bitemyapp.com/posts/2014-04-11-aeson-and-user-created-
types.html)

Can't do this without polymorphism and higher-kinded types.

~~~
biscarch
I'm using this approach for a library that is currently in development. It
works very well.

------
asuffield
Welcome to the world of languages with type systems that don't suck. It's
going to be a fun ride, and if you think _this_ is cool, you're going to be
really excited by the other languages we've got in here.

It continually amazes me that people are willing to put up with Java.

~~~
zak_mc_kracken
If you are putting Go in the category of languages with a type system that
doesn't suck, you probably need to study more languages.

Go has a few nice things going for it but its type system was clearly designed
by people who stopped paying attention to type theory and compiler design in
the late 90's.

~~~
asuffield
I wouldn't say it's exactly brilliant - but it's just missing all the really
cool stuff, rather than being buggy. It does what it's trying to do, and then
stops. It's a bit like C in that regard (and unlike C++, Java, and C#, which
tried to do something much bigger and didn't get it right).

It's also a bit like working with first-order propositional logic - well-
founded and with its own unique simplicity, but you can't say everything with
it and have alternatives.

So yes, I'd say that the type system of Go doesn't suck. It's not very good,
and there are so many better things out there (rust, I'm looking at you), but
it's a long way from being a disaster.

------
MaysonL
The trouble with implicit interfaces is maintainability: suppose Awesome gets
a func PerformAwesomeness() added to it: what then happens to the code that
thinks myType is Awesome?

Not too bad when it's all in one source file, but get a few megabytes of code
spread through a few thousand source files, and you've got a formula for chaos
and heartburn.

~~~
thrownaway2424
Not sure what you are getting at. If you add something to the interface of
Awesome, then any call site which passes a thing not having a
PerformAwesomeness() method will fail to compile.

~~~
danieldk
Unless you rely on introspection, which happens a lot when your language does
not support generics.

~~~
NateDad
No, it really doesn't happen a lot. If it does, you're doing it wrong.

~~~
danieldk
If you don't have parametric polymorphism, you only have two options to
implement new containers: a new implementation for each type or using
interface{}. The first leads to a lot of duplicate code, the latter requires
you to use introspection to use safely.

So, it does happen a lot, or you are making duplicate code.

~~~
NateDad
Or you just don't need polymorphic containers that often (other than the ones
that go already gives you).

------
skywhopper
So Go has duck-typing, and semantic capitalization, just like many other
languages.

~~~
ryanobjc
for me, the built in goroutines is what moves the needle. The rest of the
stuff is very nice, but built-in concurrency is pretty nice.

Yes I know about Erlang, no I won't touch Erlang again.

~~~
rdtsc
> Yes I know about Erlang, no I won't touch Erlang again.

Curious, what makes you say that?

~~~
ryanobjc
Strings basically. I ended up joining Google back when, and ultimately I
realized that "the web = strings" and Erlang is particularly bad at that. 128
bits for a 7-bit ascii character?

At the time, there was no good binary<->string utf8 libraries, not sure what
the state of the art is now.

------
myg204
Interesting to see surprise usages like that for such a small/simple language
like Go; makes you wonder about the amounts of trickeries available in more
complex languages.

------
NateDad
One of the nicest things about Go interfaces is that they encourage SMALL
interfaces. In explicit interface implementations, you end up throwing
everything including the kitchen sink in the interface, because you might need
it somewhere the type is used.

In Go, interfaces are small, and focused more on the _function_ rather than
the type. The function defines the methods it needs. So you can have a hundred
small interfaces with one or two methods each, and a small handful of types
that implement some percentage of those interfaces. Small interfaces makes
your functions a lot more flexible. If all you need is a Read() method and a
Close() method, instead of a huge number of potentially type-specific methods,
then your method that takes a ReadCloser can be used by a lot more types.

You can do that in languages with explicitly implemented interfaces, but it
means you need to write down that your type implements these 40 interfaces...
and that's a hassle that isn't really needed or useful.

------
shoo
For the second example, the non-implementable public interface, is there a way
to allow implementations when testing?

naively, if i define a non-implementable public interface as described in the
article inside `foo.go` and put some test code next to it in `foo_test.go`
that attempts to implement the interface with a special test version, then as
we might expect, that doesn't work. if i put test code inside `foo.go` itself,
`go test` doesn't appear to collect the test.

(i have no experience with go, apologies if i am missing something very
obvious)

~~~
helper
Your example of `foo.go` and `foo_test.go` would actually work the way you
want. In go, tests are in the same namespace as the code they are testing so
they have access to private members.

~~~
shoo
Ah, thank you. Where i was going wrong was declaring `foo_test.go` to be a
separate package from `foo.go`. When i write `package foo` at the head of both
`foo.go` and `foo_test.go` this works fine.

------
mamcx
As asked in [http://programmers.stackexchange.com/questions/234900/go-
lik...](http://programmers.stackexchange.com/questions/234900/go-like-
interfaces-multi-methods-make-sense)

I wonder if make sense to merge the julia multi-methods + GO interfaces.

------
lnanek2
Honestly, I feel the version where he defines the struct as usual is clearer,
simpler, and more maintainable. Other programmers will understand it
immediately without thought. Allowing weird fancy ways like he raves about to
save a couple lines of code is really a drawback in enterprise software
development.

------
philsnow
the purpose is to not be able to use the interface outside the module, right?
why wouldn't you just use an interface type with a lowercase name, which
wouldn't be visible outside the module?

~~~
bslatkin
You want to be able to use the interface outside the module, but not allow
anyone else to implement that interface.

