Avoiding "stuttering" code

1,277 views
Skip to first unread message

Mick Killianey

unread,
Dec 6, 2010, 8:36:16 AM12/6/10
to golang-nuts
One of the big laugh lines in early Go presentations was this one:
foo.Foo *foo = new foo.Foo(foo.FOO_INIT)

and yet I'm finding out that my Go code is suffering from exactly this
problem...it seems to have merely shuffled around the foos:

import foo "foo"
foo := foo.Foo{foo.FOO_INIT}

Are there any plans to reduce this stuttering? For example, an import
syntax like Java/Python (allowing the user to pick out specific
symbols from a package) could reduce the duplication in much of my
code by allowing me to suffer once in my imports:
import (
Foo "foobar.com/hg/foo.Foo"
FOO_INIT "foobar.com/hg/foo.FOO_INIT"
)
foo := Foo(FOO_INIT)

I'd especially love to be able to use such a syntax for types:
import (
Error "os.Error"
Reader "io.Reader"
Buffer "bytes.Buffer"
)

Has this been discussed?

I realize that for interfaces, this isn't necessary, since I can use
this trick:

type Error interface { os.Error }
type Reader interface { io.Reader }

But this doesn't work for most structs (like bytes.Buffer or os.File)
because of non-public fields. Are there similar tricks that *do* work
for structs? What about funcs/vars/consts?


chris dollin

unread,
Dec 6, 2010, 8:43:26 AM12/6/10
to Mick Killianey, golang-nuts
On 6 December 2010 13:36, Mick Killianey <mickey.k...@gmail.com> wrote:
> One of the big laugh lines in early Go presentations was this one:
>    foo.Foo *foo = new foo.Foo(foo.FOO_INIT)
>
> and yet I'm finding out that my Go code is suffering from exactly this
> problem...it seems to have merely shuffled around the foos:
>
>    import foo "foo"
>    foo := foo.Foo{foo.FOO_INIT}
>
> Are there any plans to reduce this stuttering?

How about writing

import "foo"

f := foo.Foo{foo.INIT}

And if most Foos are INIT,

f := foo.Make()

(Yes, I realise some of those choices work for Java too.)

Chris

--
Chris "allusive" Dollin

yy

unread,
Dec 6, 2010, 8:58:13 AM12/6/10
to Mick Killianey, golang-nuts
2010/12/6 Mick Killianey <mickey.k...@gmail.com>:

> I'd especially love to be able to use such a syntax for types:
>    import (
>        Error "os.Error"
>        Reader "io.Reader"
>        Buffer "bytes.Buffer"
>    )
>

Is this "stuttering"? Maybe you picked a bad example, or maybe we just
see things different, but I think os.Error, io.Reader and bytes.Buffer
are very appropriate names. I don't feel any need to short them,
removing the package name removes valuable information.

--
- yiyus || JGL . 4l77.com

chris dollin

unread,
Dec 6, 2010, 9:06:29 AM12/6/10
to Mick Killianey, golang-nuts
On 6 December 2010 13:43, chris dollin <ehog....@googlemail.com> wrote:

> How about writing
>
>    import "foo"
>
>    f := foo.Foo{foo.INIT}
>
> And if most Foos are INIT,
>
>    f := foo.Make()

Or ensure that foo.INIT is zero.

Jessta

unread,
Dec 6, 2010, 9:04:59 AM12/6/10
to Mick Killianey, golang-nuts
On Tue, Dec 7, 2010 at 12:36 AM, Mick Killianey
<mickey.k...@gmail.com> wrote:
>    import (
>        Foo "foobar.com/hg/foo.Foo"
>        FOO_INIT "foobar.com/hg/foo.FOO_INIT"
>    )
>    foo := Foo(FOO_INIT)

"Namespaces are one honking great idea -- let's do more of those!"
- import this

It's generally a good idea to actually use the package name as part of
the name of something.
foo.FOO_INIT is kind of silly, and would be better to be just foo.INIT
foo.Foo could be obtained with foo.Make() or foo.New() etc.

hiding the namespaces seems like a great idea now, saving you a few
characters. But you'll cry later as your program gets bigger and
things start to clash.

Hiding well known types behind your own types makes reading your code
that much harder.
People will curse.

- jessta

--
=====================
http://jessta.id.au

Mickey Killianey

unread,
Dec 6, 2010, 9:31:48 AM12/6/10
to Jessta, golang-nuts

jessta, I think you're missing the point of your own Python reference.

Yes, namespaces are great, but even Python found it important to allow:

  from other.namespace import Foo

Which is exactly what I'm asking for.

Mickey Killianey

unread,
Dec 6, 2010, 9:35:31 AM12/6/10
to Jessta, golang-nuts

Oh, and as for the sanctity of naming, it's already the case that if I want to import "foo/x" and "bar/x", I have to rename to avoid x clashes.

I don't see this as any different.

On 6 Dec 2010 14:04, "Jessta" <jes...@jessta.id.au> wrote:

chris dollin

unread,
Dec 6, 2010, 9:40:13 AM12/6/10
to Mickey Killianey, Jessta, golang-nuts
On 6 December 2010 14:35, Mickey Killianey <mic...@killianey.com> wrote:
> Oh, and as for the sanctity of naming, it's already the case that if I want
> to import "foo/x" and "bar/x", I have to rename to avoid x clashes.

Which x was this?

Chris

--
Chris "curious" Dollin

Mickey Killianey

unread,
Dec 6, 2010, 9:28:29 AM12/6/10
to yy, golang-nuts

I'll concede that the first "bytes.Buffer" I see is somewhat useful, but after I know which Buffer we're using, I'd really prefer to abbreviate this to just Buffer, or pick my own name, like:

import BBuffer "bytes.Buffer"

The inability to do this seems to have already led to some questionable naming choices in the Go packages.  For example, if it was possible to do this:

import ( Bench "testing.Benchmark")

Then I bet nobody would have let the testing package get away with a type called B.  (I'm not alone in my distaste for "testing.B", am I?)

BTW, I'll repeat my request: is there anything like my interface trick...

type MyName interface { otherpkg.Name }

...that works for structs/consts/vars?

Mickey Killianey

unread,
Dec 6, 2010, 9:44:58 AM12/6/10
to Jessta, golang-nuts

I stand corrected: the Python equivalent of what I asked for is:

from other.namespace import TheirName as MyName

I think the point is still roughly the same:  is it that unreasonable to want to bring frequently used names into my namespace, on my terms, to avoid "testing.B"?

On 6 Dec 2010 14:31, "Mickey Killianey" <mic...@killianey.com> wrote:

jessta, I think you're missing the point of your own Python reference.

Yes, namespaces are great, but even Python found it important to allow:

  from other.namespace import Foo

Which is exactly what I'm asking for.


>
> On 6 Dec 2010 14:04, "Jessta" <jes...@jessta.id.au> wrote:
>

> On Tue, Dec 7, 2010 at 12:36 AM,...

André Moraes

unread,
Dec 6, 2010, 9:32:28 AM12/6/10
to Mick Killianey, golang-nuts
Python recommends use of namespace (as pointed by Jessta).

In Java, as far as I remember, only Static declarations can be
imported. And I don't se the reason why Math.PI is worse than PI.

In go you don't need to rename you packages (you can, but this is
required only when two packages have the same name).

Different from python which you need to reference the entire
namespace, in go only the last package name goes public, if two
packages have the same name create an alias for one of them.

In Go, you can reference everything with a <namespace>.<thing> this is
very nice. In java for instance, if you have two classes one of then
you import and reference using only the classname and the other you
need to write the entire namespace.

import br.com.foo.Bar

bar = new br.com.foo2.Bar(); // this is not practical.

--
André Moraes
http://andredevchannel.blogspot.com/

Matt Joiner

unread,
Dec 6, 2010, 9:53:55 AM12/6/10
to Mickey Killianey, Jessta, golang-nuts
I think the stuttering indicates the module system is being used incorrectly. If you're exporting Foo from foo, you should probably be treating the module as the object, this leaves you with:

foo := foo.New(foo.INIT)

Then you want to use the zero-values as your init, or the fact that New is now a function:

foo := foo.New()

And then if you're calling your Foo, foo, it implies you probably only have one of them:

foo.Global

Or that you may have more than one, and need to refine your name:

bar := foo.New()

While I find the python import syntax handy, I think there's real value in aggregating type names and using the module they're found in. There's nothing worse than reading someone else's code and seeing BBuffer and having to dig that type up to find it's a typedef, or an from X import Y as Z. Seeing math.PI will never lead to confusion (and if it does the author of the code needs a stern talking to), but PI could be anything.

The reverse situation is what happens in C++, where its impossible to get anything done without typedefs and namespace assigns due to the ridiculously long signatures floating about. Just look at any Boost library. I look forward to seeing code with such names as gtk.Window, http.Get, fuse.Operations, and knowing exactly what is meant without having to check imports, headers and typedefs.

Mickey Killianey

unread,
Dec 6, 2010, 9:56:26 AM12/6/10
to Matt Joiner, golang-nuts, Mickey Killianey, Jessta

So what's your reaction to testing.B?

On 6 Dec 2010 14:54, "Matt Joiner" <anac...@gmail.com> wrote:

I think the stuttering indicates the module system is being used incorrectly. If you're exporting Foo from foo, you should probably be treating the module as the object, this leaves you with:

foo := foo.New(foo.INIT)

Then you want to use the zero-values as your init, or the fact that New is now a function:

foo := foo.New()

And then if you're calling your Foo, foo, it implies you probably only have one of them:

foo.Global

Or that you may have more than one, and need to refine your name:

bar := foo.New()

While I find the python import syntax handy, I think there's real value in aggregating type names and using the module they're found in. There's nothing worse than reading someone else's code and seeing BBuffer and having to dig that type up to find it's a typedef, or an from X import Y as Z. Seeing math.PI will never lead to confusion (and if it does the author of the code needs a stern talking to), but PI could be anything.

The reverse situation is what happens in C++, where its impossible to get anything done without typedefs and namespace assigns due to the ridiculously long signatures floating about. Just look at any Boost library. I look forward to seeing code with such names as gtk.Window, http.Get, fuse.Operations, and knowing exactly what is meant without having to check imports, headers and typedefs.



On Tue, Dec 7, 2010 at 1:35 AM, Mickey Killianey <mic...@killianey.com> wrote:
>

> Oh, and as for ...

Mickey Killianey

unread,
Dec 6, 2010, 9:54:46 AM12/6/10
to chris dollin, golang-nuts, Mickey Killianey, Jessta

Jessta's point was that reducing io.Reader to Reader would be an affront, because io.Reader is, somehow, its "true" name.

My point is that there will always be collisions in package names.  I'll discover that I'll need to use "github.com/apache/ioutil" and "io/ioutil" in the same file, and only one could get to be the "ioutil" namespace. But that's too crude...I'd really rather do:

import (
  ReadNormalFile "io/ioutil.ReadFile"
  ReadGzippedFile "my/ioutil.ReadGzipFile"
)

So that it isn't a choice of which package I want...it's a choice of what symbols I want.

On 6 Dec 2010 14:40, "chris dollin" <ehog....@googlemail.com> wrote:

On 6 December 2010 14:35, Mickey Killianey <mic...@killianey.com> wrote:

> Oh, and as for the sancti...

Matt Joiner

unread,
Dec 6, 2010, 10:08:16 AM12/6/10
to Mickey Killianey, golang-nuts, Jessta
It looks to me like testing should read "test". And that B wants to be Benchmark, but a function by that name already exists. If the benchmarking was broken out of since the test/bench related stuff don't depend on one another I'd have:

testing.B->bench.Run
testing.Benchmark*->bench.Case

However neither appear to be that great an improvement, and in the 5 minutes it took me to familiarize myself with the testing module, I will now know exactly what is meant by any of the testing.* types without having to refer to imports.

chris dollin

unread,
Dec 6, 2010, 10:11:39 AM12/6/10
to Mickey Killianey, golang-nuts, Jessta
On 6 December 2010 14:54, Mickey Killianey <mic...@killianey.com> wrote:
> Jessta's point was that reducing io.Reader to Reader would be an affront,
> because io.Reader is, somehow, its "true" name.
>
> My point is that there will always be collisions in package names.  I'll
> discover that I'll need to use "github.com/apache/ioutil" and "io/ioutil" in
> the same file, and only one could get to be the "ioutil" namespace. But
> that's too crude...

Well, opinions clearly differ; it's a nice straightforward locally-controlled
mechanism useful in infrequent situations.

I think that the Go package naming technique is a really good
95% solution for namespacing and I'm not really worried about the
5% left over.

(I happen to have devised a very similar solution for a programming
language I was co-designing more than ten years ago, so I'm biased.)

Chris

--
Chris "numbers made up on demand" Dollin

Matt Joiner

unread,
Dec 6, 2010, 10:12:04 AM12/6/10
to Mickey Killianey, golang-nuts, Jessta
I should add that testing.B would be more familiar than import BenchmarkRunInstance as MyPreferredName, where MyPreferredName differs by author's taste, and time of year.

Jessta

unread,
Dec 6, 2010, 10:35:04 AM12/6/10
to Mickey Killianey, yy, golang-nuts
On Tue, Dec 7, 2010 at 1:28 AM, Mickey Killianey <mic...@killianey.com> wrote:
> BTW, I'll repeat my request: is there anything like my interface trick...
>
> type MyName interface { otherpkg.Name }
>
> ...that works for structs/consts/vars?
You can embed types on structs:
type MyName struct {otherpkg.Name}

And create variables to point to things:
const myconst = otherpkg.ConstName
var printf = fmt.Printf

Bill Burdick

unread,
Dec 6, 2010, 10:47:06 AM12/6/10
to Mick Killianey, golang-nuts
On Mon, Dec 6, 2010 at 7:36 AM, Mick Killianey <mickey.k...@gmail.com> wrote:
One of the big laugh lines in early Go presentations was this one:
   foo.Foo *foo = new foo.Foo(foo.FOO_INIT)

and yet I'm finding out that my Go code is suffering from exactly this
problem...it seems to have merely shuffled around the foos:

   import foo "foo"
   foo := foo.Foo{foo.FOO_INIT}

If foo isn't too large, you can import it into the current namespace for this file:

import . "foo"

foo := Foo{FOO_INIT}

For packages that YOU write, you can structure them in bite-sized chunks to facilitate that.  Not as nice as being able to import specific classes, because the package designer has to plan in advance what they think you might need and it doesn't lend itself well to large libraries.  But you could split a large library into a several library "cluster", with this sort of importing in mind.  Then, users would have to use different import lines to access different parts of the cluster -- kind of like multiple imports in Java.


Bill

Mickey Killianey

unread,
Dec 6, 2010, 11:43:39 AM12/6/10
to Matt Joiner, golang-nuts, Mickey Killianey, Jessta

My opinion is that testing.B is just one example of a category of poor naming choices encouraged by the namespace syntax (and I'm still convinced that anyone who doesn't find the name testing.B at least a *little* wrong should get themselves tested for toxic levels of Go Kool-Aid).

If there would have been a groundswell of support for this, I would have suggested "hey, isn't this a great opportunity to work on a deprecation mechanism for Go, and give it a test run by renaming testing.T and B to...well...just about *anything* else?"

However, I'm willing to concede that my viewpoint seems to be in the minority, so rather than rail against the language, I'll return to my original question:  is there a way to achieve this today *within* Go's syntax?

With interfaces, I think I'm content with:
    type Foo interface { foo.Foo }
As in:
    type DAG interface { graphs.ArrayBackedDirectedAcyclicGraph }
Not only is this easier for me to type and read, but if I want to switch to graphs.NodeBasedDirectedAcyclicGraph during development, I can make that change with a minimum of fuss...switch the type declaration and fix whatever doesn't compile.

But with consts and vars, I'm at a loss...I think the best I can do is use a reference:
    var SWAVLN = &foo.SomethingWithAVeryLongName
And dereference it at runtime, which is mostly fine.

And with structs...I think the best I can manage is:
    type FooRef *foo.FooStructWithPrivateFields

Which means that I can't accept or return by value.

Anyone got better suggestions for the non-interface cases?

On 6 Dec 2010 15:12, "Matt Joiner" <anac...@gmail.com> wrote:

I should add that testing.B would be more familiar than import BenchmarkRunInstance as MyPreferredName, where MyPreferredName differs by author's taste, and time of year.



On Tue, Dec 7, 2010 at 2:08 AM, Matt Joiner <anac...@gmail.com> wrote:
>

> It looks to me like t...

Mickey Killianey

unread,
Dec 6, 2010, 11:55:32 AM12/6/10
to Jessta, golang-nuts, Mickey Killianey, yy

Thanks for the reminder about func s...good point.

As for const FOO = other.FOO, does that always work, or could it end up that FOO points to a separate copy of other.FOO, so that:
   FOO == other.FOO
But
   &FOO != &other.FOO

Is there a runtime guarantee one way or the other?

Again, thanks for the thoughtful response, both you and everyone else...this group has been really helpful as I've gotten started in Go!

On 6 Dec 2010 15:35, "Jessta" <jes...@jessta.id.au> wrote:

On Tue, Dec 7, 2010 at 1:28 AM, Mickey Killianey <mic...@killianey.com> wrote:

> BTW, I'll repeat my...

nsf

unread,
Dec 6, 2010, 12:16:32 PM12/6/10
to golan...@googlegroups.com

Think about other people please.

import (
MegaThing "bytes.Buffer"
)

I don't want to see a code like this. In the Go language you can rename
package names, that is ok, but you can't rename other things. It is
amazing.

And your FOOish example is really bad. Rob Pike's example as far as I
understand was partly a joke. But you know, all jokes are 50% truth.
There is a problem with verbosity in Java, it's not just about
initializing things and there is no such problem in Go. I think you've
been coding too much Java lately.

chris dollin

unread,
Dec 6, 2010, 12:46:34 PM12/6/10
to Mickey Killianey, Jessta, golang-nuts, yy
On 6 December 2010 16:55, Mickey Killianey <mic...@killianey.com> wrote:
> Thanks for the reminder about func s...good point.
>
> As for const FOO = other.FOO, does that always work, or could it end up that
> FOO points to a separate copy of other.FOO, so that:
>    FOO == other.FOO
> But
>    &FOO != &other.FOO
>
> Is there a runtime guarantee one way or the other?

consts in Go are rather limited; numbers or strings.

(And you can't take their addresses either.)

So no separate copies ...

Andrew Gerrand

unread,
Dec 6, 2010, 6:49:42 PM12/6/10
to Mick Killianey, golang-nuts
On 7 December 2010 00:36, Mick Killianey <mickey.k...@gmail.com> wrote:
>    import foo "foo"
>    foo := foo.Foo{foo.FOO_INIT}

It's been said in some form already, but this is a terrible example.
Go packages aren't structured or used in this way. (And, a minor
point, you don't need to specify the name 'foo' in your import line.
The package should do that itself.)

When authoring a go package it is the convention to consider your
exported names will be prefixed by the package name. When I wrote the
archive/zip package, I named the type that reads from zip files
Reader, not ZipReader. That's because the package is imported as
'zip', and so the type appears to its clients as zip.Reader. I don't
see any stuttering here.

I find your particular criticism surprising, as IMO Go's approach to
imports is one of the sanest I've seen in any language. I guess I'm
biased, though.

This type of python import line
from other.namespace import Foo
is A Bad Idea and has, in my experience, led to some truly unreadable code.

With that said, you can achieve the same effect in Go (with functions
or variables) like so:
import "package"
var Foo = package.Foo

To address your point of conflicting package names: In all the go code
I've written to date I've never once had to rename an import unless I
was doing something really weird. Doing weird things _should_ feel
weird; we shouldn't tailor the language to odd edge-cases.

Andrew

Matt Joiner

unread,
Dec 6, 2010, 11:43:10 PM12/6/10
to Andrew Gerrand, Mick Killianey, golang-nuts
This mirrors my thinking also.

Serge Hulne

unread,
Dec 7, 2010, 12:17:15 AM12/7/10
to golang-nuts
>
> I find your particular criticism surprising, as IMO Go's approach to
> imports is one of the sanest I've seen in any language.
>

I agree.

> This type of python import line
>   from other.namespace import Foo
> is A Bad Idea and has, in my experience, led to some truly unreadable code.
>
>

I agree too: I also find that an explicit mention of the name of an
imported package avoids the "Where does that come from, now ?" effect.

In that respect, Go is easier to read (less ambiguous) than Python
(for the above mentioned reason), Java (for a similar reason), and C++
("using namespace ...").

It is even clearer than C in that respect: Once you have a lot of
"#include <...>", it becomes hard to guess what comes from where
because it is implicit rather that explicit.

Serge

Mick Killianey

unread,
Dec 7, 2010, 6:24:23 AM12/7/10
to golang-nuts
Oh, of course...duh. Excellent point. Thanks for setting me
straight!

Mickey Killianey

unread,
Dec 10, 2010, 6:38:58 AM12/10/10
to Andrew Gerrand, golang-nuts
On 6 December 2010 23:49, Andrew Gerrand <a...@golang.org> wrote:
On 7 December 2010 00:36, Mick Killianey <mickey.k...@gmail.com> wrote:
>    import foo "foo"
>    foo := foo.Foo{foo.FOO_INIT}

It's been said in some form already, but this is a terrible example.

Yes it is, as several people felt compelled to point out, which makes me wonder if they've missed the point.

Rob's example was *intentionally* terrible.  My translation *intentionally* preserved the terribleness.  Yes, clearly the author of the "foo" package is to be blamed.  But the Go doesn't magically stop people from writing awkward code.  Even the great ones write some clunkers, and at some point it's inevitable you'll find yourself using an ugly library like foo because It Gets The Job Done.

So, this thread was asking:  when you have to use an awkward package like this, can you lessen its awkwardness in your own code?

And I think the conclusion was that, except for structs with unexported fields, local aliases are easy to do.
 
Go packages aren't structured or used in this way.

Well...I would agree with /aren't/shouldn't be/.  But some *are* structured in this way.  For example, I don't see a way to avoid this signature:

    func FindTokens(t* template.Template, r *regexp.Regexp) *list.List

When authoring a go package it is the convention to consider your
exported names will be prefixed by the package name. When I wrote...

You may say that, but when I look at the codebase, even within the same general area of the code, like the containers, I see three out of four stutterers:
    vector.Vector
    ring.Ring
    list.List
    heap.Interface

If you *happen* to have a name that neatly.Divides into two.Parts, then great.  But if your problem domain doesn't naturally read that way (as the "containers" packages suggest), this issue is pretty common.Common.

Noah Evans

unread,
Dec 10, 2010, 9:06:50 AM12/10/10
to mic...@killianey.com, Andrew Gerrand, golang-nuts
What happens when the same people that wrote the terrible packages
start writing terrible bindings that obscure their already obtuse
code?

Other people have said it in the beginning of the thread, but it bears
repeating, you almost never see a ring.Ring or a list.List, you
usually do:

r := ring.New() or l := list.New()

Vectors are a slightly different case because you genuinely need them
because of the different vector types, vector.IntVector etc...

Have you looked through any of the go programs in $GOROOT/src/cmd like
goinstall, gofmt or godoc? I think they would go a long way towards
making you feel better about the verbosity of the language.

Noah

Uriel

unread,
Dec 11, 2010, 6:14:26 AM12/11/10
to Noah Evans, mic...@killianey.com, Andrew Gerrand, golang-nuts
On Fri, Dec 10, 2010 at 3:06 PM, Noah Evans <noah....@gmail.com> wrote:
> What happens when the same people that wrote the terrible packages
> start writing terrible bindings that obscure their already obtuse
> code?
>
> Other people have said it in the beginning of the thread, but it bears
> repeating, you almost never see a ring.Ring or a list.List, you
> usually do:
>
> r := ring.New() or l := list.New()
>
> Vectors are a slightly different case because you genuinely need them
> because of the different vector types, vector.IntVector etc...

No, Vectors are different because you should not be using Vectors, you
should be using slices.

uriel

peterGo

unread,
Dec 11, 2010, 11:37:06 AM12/11/10
to golang-nuts
Uriel,

On Dec 11, 6:14 am, Uriel <ur...@berlinblue.org> wrote:

> Vectors are different because you should not be using Vectors, you
> should be using slices.

The underlying types for the vector package types are slices.

Peter

On Dec 11, 6:14 am, Uriel <ur...@berlinblue.org> wrote:

Nigel Tao

unread,
Dec 11, 2010, 8:10:39 PM12/11/10
to mic...@killianey.com, Andrew Gerrand, golang-nuts
On 10/12/2010, Mickey Killianey <mickey.k...@gmail.com> wrote:
> On 6 December 2010 23:49, Andrew Gerrand <a...@golang.org> wrote:
>> On 7 December 2010 00:36, Mick Killianey <mickey.k...@gmail.com>
>> wrote:
>> > import foo "foo"
>> > foo := foo.Foo{foo.FOO_INIT}
>>
>> It's been said in some form already, but this is a terrible example.
>
> Yes it is, as several people felt compelled to point out, which makes me
> wonder if they've missed the point.
>
> Rob's example was *intentionally* terrible. My translation *intentionally*
> preserved the terribleness.

Rob's example was intentionally terrible, but it came from *real*
code, substituting Foo for whatever the original library was. IIRC it
was C++, but it might have been Java. The terribleness was an
unintentional byproduct of the C++ naming style.

You've recreated the terribleness in Go code, but as many people have
already noted, real Go code should not look like that.

Mickey Killianey

unread,
Dec 13, 2010, 10:43:33 AM12/13/10
to Nigel Tao, golang-nuts, Andrew Gerrand, mic...@killianey.com

Yes, the foo package in this example is awkward to use...Rob wrote it that way intentionally, and yes, I translated the awkwardness intentionally.  But those of you who continue to criticize the package...you're missing the point.

Just as it is possible to write *elegant* libraries in Go (as in Java or C++ or Python or whatever Rob's example is), it is also possible to write *awkward* APIs in Go (as in any of those other languages).  There's nothing magical about Go that disallows mediocre code.

Not all programmers write elegant code all of the time, and there will be times when you find yourself needing to use a mediocre Go library, because, for better or worse, it works.  Complaining that "real Go code doesn't look like this" is counterfactual idealism.

This thread merely asks what one can constructively do to make life better when you're stuck as the *user* of a package with a clunky API.

Other languages have explicit mechanisms that you can use to rename on import to improve local readability.  Yes, it's possible to abuse those mechanisms.  But calling them evil (as some did on this thread) is being a bit overdramatic.

Go only has one explicit mechanism (the import declaration), but this thread discussed several *implicit* mechanisms that fall out of the language spec.  These tricks are worth knowing, not because you expect to do it often, but because on the unusual occasion that merits it, it's a handy tool to have.



On 12 Dec 2010 01:10, "Nigel Tao" <nigel.t...@gmail.com> wrote:

On 10/12/2010, Mickey Killianey <mickey.k...@gmail.com> wrote:

> On 6 December 2010 23:49, Andr...

Bill Burdick

unread,
Dec 13, 2010, 11:54:49 AM12/13/10
to peterGo, golang-nuts
On Sat, Dec 11, 2010 at 10:37 AM, peterGo <go.pe...@gmail.com> wrote:
Uriel,

On Dec 11, 6:14 am, Uriel <ur...@berlinblue.org> wrote:

> Vectors are different because you should not be using Vectors, you
> should be using slices.

The underlying types for the vector package types are slices.

Peter

I find that sometimes it's more convenient to use Vectors and sometimes more convenient to use slices.  I think this code works a lot better with Vectors, for instance:

package main

import . "container/vector"
import "fmt"

func main() {
fmt.Println(Vector{1, 2, 3})
}


Saying "Vector([]interface{}{1, 2, 3})" is more noisy than "Vector{1,2,3}" and really, they do (mostly) the same thing.  The main difference that I've had to watch out for is with pointers; Vectors and slices of interface{} arrays have the same underlying type, but pointers to Vectors and pointers to slices of interface{} arrays do not:


package main

import . "container/vector"
import "fmt"

func main() {
v := Vector{1,2,3}
var a []interface{} = v
var pv *Vector = &v
var pa *[]interface{} = (*[]interface{})(pv)

fmt.Println(v)
fmt.Println(a)
fmt.Println(pv)
fmt.Println(pa)
}


So if you have a choice between vector pointers and interface{} array slice pointers, sometimes it's easier to use vector pointers, because you don't have to use conversions all over the place.


Bil

Andrew Gerrand

unread,
Dec 13, 2010, 5:08:22 PM12/13/10
to Mickey Killianey, Nigel Tao, golang-nuts
On 14 December 2010 02:43, Mickey Killianey <mic...@killianey.com> wrote:
> Just as it is possible to write *elegant* libraries in Go (as in Java or C++
> or Python or whatever Rob's example is), it is also possible to write
> *awkward* APIs in Go (as in any of those other languages).  There's nothing
> magical about Go that disallows mediocre code.
>
> Not all programmers write elegant code all of the time, and there will be
> times when you find yourself needing to use a mediocre Go library, because,
> for better or worse, it works.  Complaining that "real Go code doesn't look
> like this" is counterfactual idealism.
>
> This thread merely asks what one can constructively do to make life better
> when you're stuck as the *user* of a package with a clunky API.

Okay. I would suggest you write a wrapper library that makes the
clunky API cleaner. Or, better still, fix the clunky API and push the
changes upstream.

Making bad code easier to use does little more than encourage
people to write bad code. Let's not complicate the language for that
purpose.

> Other languages have explicit mechanisms that you can use to rename on
> import to improve local readability.  Yes, it's possible to abuse those
> mechanisms.  But calling them evil (as some did on this thread) is being a
> bit overdramatic.

Perhaps not "evil", but definitely not in the spirit of the Go language.

Andrew

Reply all
Reply to author
Forward
0 new messages