gofmt output, why is it so?*

991 views
Skip to first unread message

yuk...@gmail.com

unread,
Nov 30, 2009, 1:39:25 AM11/30/09
to golang-nuts
I'm pretty new to gofmt, I heard that all the source files for the packages are gofmted, so I tried to pass through gofmt my source files and I was very surprised with the result!?

I got this:

const (
_ PrintMode = iota;
PRINT_PT; // for point print
PRINT_NT; // for node type print
)

1. Why so many tabs for this const declarations? It was just as simple as

const (
_ PrintMode = iota;
PRINT_PT; // for point print
PRINT_NT; // for node type print
PRINT_BO; // for both NT(PT)
)


Then, for imports, I got this:

import (
"rand";
"fmt";  <-- note that semicolon is still intact
)

But

if i == 0 && y == j {
y--  <-- semicolon removed
} else if j == 0 && x == i {
x--  <-- semicolon removed
}

2. Why is semicolon removed on the program statements, but not on the import statements?


Then on variable declarations

type Player struct {
name string; <-- two tabs between "name" and "string"
num_moves int;  <-- one tab between "num_moves" and "int"
position Point; <-- one tab
}


3. Why does gofmt put tabs between names of fields and their types? Moreover, some had 2 tabs and some had 1 tab. 
How if the viewer does not use a fixed tab size, doesn't it make the source look uglier?


func (this *Player) SetName(name string) { this.name = name }

4. A tab between function prototype and the body, and the body is made on the same line? 
I don't get it why newlines are removed in this case.


if (i != 0 || j != 0) && rand.Int()%RAND_FACT == 0 ... 

5. Before gofmt, there is a space before and after "%". Why does it remove the spaces around %, but not around +, *, && and other operators?


Personally I pretty much disappointed with those points, may someone help me understand the rationales behind them. I'm sure there are great reasons from the gofmt creators.

-yuku

yuk...@gmail.com

unread,
Nov 30, 2009, 1:44:12 AM11/30/09
to golang-nuts
It seems that tabs from my email are not displayed correctly on the web interface, let me replace the significant tabs by "<tab>".


I'm pretty new to gofmt, I heard that all the source files for the packages are gofmted, so I tried to pass through gofmt my source files and I was very surprised with the result!?

I got this:

const (
_<tab><tab>PrintMode<tab>= iota;
PRINT_PT;<tab><tab><tab>// for point print
PRINT_NT;<tab><tab><tab>// for node type print
)

1. Why so many tabs for this const declarations? It was just as simple as

const (
_ PrintMode = iota;
PRINT_PT; // for point print
PRINT_NT; // for node type print
PRINT_BO; // for both NT(PT)
)


Then, for imports, I got this:

import (
"rand";
"fmt";  <-- note that semicolon is still intact
)

But

if i == 0 && y == j {
y--  <-- semicolon removed
} else if j == 0 && x == i {
x--  <-- semicolon removed
}

2. Why is semicolon removed on the program statements, but not on the import statements?


Then on variable declarations

type Player struct {
name<tab><tab>string; <-- two tabs between "name" and "string"
num_moves<tab>int;  <-- one tab between "num_moves" and "int"
position<tab>Point; <-- one tab
}


3. Why does gofmt put tabs between names of fields and their types? Moreover, some had 2 tabs and some had 1 tab. 
How if the viewer does not use a fixed tab size, doesn't it make the source look uglier?


func (this *Player) SetName(name string)<tab>this.name = name }

4. A tab between function prototype and the body, and the body is made on the same line? 
I don't get it why newlines are removed in this case.


if (i != 0 || j != 0) && rand.Int()%RAND_FACT == 0 ... 

5. Before gofmt, there is a space before and after "%". Why does it remove the spaces around %, but not around +, *, && and other operators?


* Personally I pretty much disappointed with those points, may someone help me understand the rationales behind them. I'm sure there are great reasons from the gofmt creators.

-yuku

Adam Langley

unread,
Nov 30, 2009, 2:13:37 AM11/30/09
to yuk...@gmail.com, golang-nuts
On Sun, Nov 29, 2009 at 10:44 PM, yuk...@gmail.com <yuk...@gmail.com> wrote:
> * Personally I pretty much disappointed with those points, may someone help
> me understand the rationales behind them. I'm sure there are great reasons
> from the gofmt creators.

Most of the reason for gofmt is to remove the need to deal with this
sort of thing. I haven't counted recently, but I think that there are
about five different C++ styles that I have to keep straight for the
different C++ projects that I work in.

Within reason, the existence of an answer to the style question is
more important than the answer itself.

> if i == 0 && y == j {
> y--  <-- semicolon removed
> } else if j == 0 && x == i {
> x--  <-- semicolon removed
> }

This is the only aspect of gofmt that I consider unreasonable at the
moment. Doing without semi-colons is a nice idea but, in practice, it
adds noise to diffs and trips me up every single time I add another
statement to a (formerly) single statement block.

> name<tab><tab>string; <-- two tabs between "name" and "string"
> num_moves<tab>int;  <-- one tab between "num_moves" and "int"
> position<tab>Point; <-- one tab

The tabs are assumed to be 8 characters wide. If you render them as
such the columns line up.

> if (i != 0 || j != 0) && rand.Int()%RAND_FACT == 0 ...
> 5. Before gofmt, there is a space before and after "%". Why does it remove
> the spaces around %, but not around +, *, && and other operators?

This mirrors the precedence of the operators.


AGL

Tor

unread,
Nov 30, 2009, 7:27:25 AM11/30/09
to golang-nuts
On Nov 30, 8:13 am, Adam Langley <a...@golang.org> wrote:
> On Sun, Nov 29, 2009 at 10:44 PM, yuk...@gmail.com <yuk...@gmail.com> wrote:

> This is the only aspect of gofmt that I consider unreasonable at the
> moment. Doing without semi-colons is a nice idea but, in practice, it
> adds noise to diffs and trips me up every single time I add another
> statement to a (formerly) single statement block.
>
> > name<tab><tab>string; <-- two tabs between "name" and "string"
> > num_moves<tab>int;  <-- one tab between "num_moves" and "int"
> > position<tab>Point; <-- one tab
>
> The tabs are assumed to be 8 characters wide. If you render them as
> such the columns line up.

Not if you're using proportional fonts, and what of those who prefer
smaller tab stops? Using tabs and filtering through the tabwriter
elastic tabstops is a great idea but it falls short in so many ways
that I would prefer if gofmt didn't try to align anything past the
initial indentation.

> > if (i != 0 || j != 0) && rand.Int()%RAND_FACT == 0 ...
> > 5. Before gofmt, there is a space before and after "%". Why does it remove
> > the spaces around %, but not around +, *, && and other operators?
>
> This mirrors the precedence of the operators.

It's still ugly. Give us some breathing space here!
Compact code is suffocating, missing white space
burns my typophile eyes.

-tor

Ben Tilly

unread,
Nov 30, 2009, 11:52:54 AM11/30/09
to Tor, golang-nuts
On Mon, Nov 30, 2009 at 4:27 AM, Tor <tor.an...@gmail.com> wrote:
> On Nov 30, 8:13 am, Adam Langley <a...@golang.org> wrote:
>> On Sun, Nov 29, 2009 at 10:44 PM, yuk...@gmail.com <yuk...@gmail.com> wrote:
[...]
>> The tabs are assumed to be 8 characters wide. If you render them as
>> such the columns line up.
>
> Not if you're using proportional fonts, and what of those who prefer
> smaller tab stops? Using tabs and filtering through the tabwriter
> elastic tabstops is a great idea but it falls short in so many ways
> that I would prefer if gofmt didn't try to align anything past the
> initial indentation.
[...]

I hate One True Formatting wars as much as the next person. Everyone
has their opinions, and what matters is mostly just being consistent.

But one of the few things there is concrete data on is that reading
comprehension is significantly better with a an indent of 2-4 spaces,
rather than a 6 or 8 space indent. This is despite the fact that
people tend to find a 6 or 8 space indent aesthetically more pleasing.
(See _Code Complete_ for details. In _Perl Best Practices_ Damian
Conway pointed to research that a 4 space indent is better than 2 for
older programmers whose eyes aren't as sharp.) As a result I am
rather unhappy that gofmt uses an 8 space indent and gives no obvious
way to change this.

Looking at the documentation I would hope that -tabwidth=4 would let
the programmer choose the style. But in my experiments that did not
change the visual output. :-(

If we're going to have a tool that enforces programming style on
people, can we please not enforce a suboptimal style? Alternately
could we provide options allowing people to choose what style to get?
Like http://perltidy.sourceforge.net/ does for Perl?

Thanks,
Ben

Weeble

unread,
Nov 30, 2009, 12:44:24 PM11/30/09
to golang-nuts
On Nov 30, 4:52 pm, Ben Tilly <bti...@gmail.com> wrote:
> Looking at the documentation I would hope that -tabwidth=4 would let
> the programmer choose the style. But in my experiments that did not
> change the visual output. :-(
>
> If we're going to have a tool that enforces programming style on
> people, can we please not enforce a suboptimal style? Alternately
> could we provide options allowing people to choose what style to get?
> Likehttp://perltidy.sourceforge.net/does for Perl?

I share your discomfort at 8 space indents. I also can't see what
benefits there are to gofmt defaulting to use tabs rather than spaces
- using tabs, code passed through anything that doesn't use 8-space
tabs will get mangled, so they are no more flexible than spaces, but
they are more fragile.

However, the reason I'm replying is to say that gofmt *does* provide
the configuration that you ask for. Use -tabwidth to tell it how wide
tabs are, but you *must* tell your editor too. The text file itself
doesn't say what the tab-stops are, it just contains tab characters
which the editor/terminal must interpret. You can also use -spaces to
tell it to indent with spaces rather than tabs.

Russ Cox

unread,
Nov 30, 2009, 1:24:03 PM11/30/09
to Tor, golang-nuts
> It's still ugly. Give us some breathing space here!
> Compact code is suffocating, missing white space
> burns my typophile eyes.

Try it for a while. Your eyes adjust, and the algorithm
isn't just "strip all white space". It has some redeeming
qualities, which your typophile eyes will pick up after a while.

http://groups.google.com/group/golang-nuts/t/1c2dac0e1ad95b96#1913cbd6c58a2bee

Russ

baldmountain

unread,
Nov 30, 2009, 1:27:11 PM11/30/09
to golang-nuts


On Nov 30, 12:44 pm, Weeble <clockworksa...@gmail.com> wrote:
> On Nov 30, 4:52 pm, Ben Tilly <bti...@gmail.com> wrote:
>
> I share your discomfort at 8 space indents.


I have a target in my makefile that has a bunch of gofmt commands.
They all look like:

gofmt -w -tabwidth=2 -spaces=true foo.go

Ta Da! Tabs are 2 spaces just like in TextMate. :D


geoff

SnakE

unread,
Nov 30, 2009, 1:40:41 PM11/30/09
to r...@golang.org, Tor, golang-nuts
2009/11/30 Russ Cox <r...@golang.org>

That's almost true.  Except, when I add a second line to a single-line block and forget to add a semicolon to the first line, gofmt won't fix this bug for me.  I think this particular rule should be changed: if a statement is on its own line, it must end with a semicolon.

Russ Cox

unread,
Nov 30, 2009, 2:28:05 PM11/30/09
to SnakE, golang-nuts
> That's almost true.  Except, when I add a second line to a single-line block
> and forget to add a semicolon to the first line, gofmt won't fix this bug
> for me.  I think this particular rule should be changed: if a statement is
> on its own line, it must end with a semicolon.

We're certainly aware of that problem.
I think the semicolon rules might be tweaked at
some point, but we like to take time to accumulate
experience with the current rules before making
changes, to avoid too much churn.

Thanks.
Russ

yuk...@gmail.com

unread,
Dec 1, 2009, 10:24:07 AM12/1/09
to baldmountain, golang-nuts
The problem with the ability to define how many spaces a tab is, is that it may make the source even uglier than unformatted in editors with different tab width settings.

Especially the field/const tabbing.

Imagine this appearance (just a simulation):

type A struct {
    bardToInteractName   string
    operation                                                       func(int) int
    numChildren                            int
}

just because gofmt uses tabwidth 2 and the editor uses tabwidth 8.


I'm still against changing tabs aside from the leading tabs. 
Why do we need to align variables with their types, if variable names are always one-word, where types can be many words. Isn't it easy enough to differentiate variable names from their types: just look for the first whitespace?

In C, yes it is sometimes not easy to see variable names because variable types are before the names. But not in Go.

2009/12/1 baldmountain <baldmo...@gmail.com>

Geoffrey Clements

unread,
Dec 1, 2009, 10:41:09 AM12/1/09
to yuk...@gmail.com, golang-nuts
That's why you use -spaces=true. It slams spaces everywhere so
everything lines up properly.

I also set tabs to 2 spaces and set the editor to always uses spaces
rather than tabs. To me tabs just cause this situation and should be
banned from code.

I agree about not aligning types. I'd rather there just be a single
space after the variable name.

If I contribute code to the main Go repository I'll run it through
gofmt with no options and accept whatever it spits out...

But for my own code, 2 space tabs everywhere. :)
--
geoff

Bob Cunningham

unread,
Dec 1, 2009, 5:55:02 PM12/1/09
to Geoffrey Clements, yuk...@gmail.com, golang-nuts
Even all spaces is not a panacea, especially if you use a proportional font (something I find desirable).

In fixed-width fonts, a space has a full 'em' width, while in most proportional fonts, the default space is a half-em. So a fixed-width 4-space indent would look like 2 spaces when using a proportional font. Hence the desire to use tabs as an indent specifier that does not depend on the particular font, just the font size.

However, there may be a simpler, more general solution: Indent Go code using Unicode "em spaces" (0x2003), and indents should look similar on all systems, independent of the font or tab width used.

I haven't yet tried this myself: Anyone know of any editors that will do this automatically? I suppose emacs can... There's nothing emacs can't do!

We may want to recommend a change to gofmt to support this style of indent, and see how it goes.

-BobC

Robert Griesemer

unread,
Dec 1, 2009, 6:28:01 PM12/1/09
to Bob Cunningham, Geoffrey Clements, yuk...@gmail.com, golang-nuts
Unfortunately the tabwriter package (which is used to align columns) cannot handle em spaces correctly: At the moment it doesn't accept non-byte "padding" chars, but even if it would, it assumes all chars have the same width. To fix this at the "file level" one would have to tell it the font, but that would make things even more complicated, and it's not clear it would even work (what's in the file may look different in an editor, and one would need pixel-accurate white space).

The "right" solution is to use (have!) editors that handle tabs like (flexible) "tab stops" and thus that show code nicely even if a proportional font is used (which I personally find desirable, too).

I am experimenting with a version that uses tabs for indentation only, and blanks (or what-have-you) elsewhere. For various reasons, aligned columns are broken across sections of different indentation; thus all code at a given tab width is uniformly indented proportional to the tab width and (at least using a fixed-width font), everything else in the respective section remains aligned independent of tab width.

Still not ideal for proportional fonts but it allows users to set the tab width to their liking and the code looks reasonable (without the need to re-apply gofmt). It also prevents the rather large gaps between columns.

We are aware that the gofmt output may not be to everybody's liking but we much prefer having a uniform and fairly reasonable style over a variety of different styles.

- gri

Bob Cunningham

unread,
Dec 1, 2009, 11:21:00 PM12/1/09
to golang-nuts
On 12/01/2009 03:28 PM, Robert Griesemer wrote:
> Unfortunately the tabwriter package (which is used to align columns)
> cannot handle em spaces correctly: At the moment it doesn't accept
> non-byte "padding" chars, but even if it would, it assumes all chars
> have the same width. To fix this at the "file level" one would have to
> tell it the font, but that would make things even more complicated, and
> it's not clear it would even work (what's in the file may look different
> in an editor, and one would need pixel-accurate white space).

Should a bug / feature request be opened against tabwriter?

Gofmt cares about character width only in the special case of indentation, which it already does with regard to tabs. Em-space would be the second width-aware character, not the first. And it would be fixed, not variable.

There should be no need to determine the font, since I believe it would be a configuration error for any editor or printer to fail to correctly display an em-space. If you get a funny square box, then the user needs a better font, something a Unicode source file should care nothing about.

However, gofmt does need to know the desired output indentation increment in em-spaces. If no count is provided, it may either be inferred from the file content (usually 2 or 4), or simply assumed to be a default value, such as 4.

As a temporary hack, we can use awk or sed to replace leading spaces and tabs with a suitable number of em-spaces, and see how the result is handled by the various editors in use. The display of a converted file should not be affected for monospace fonts (unless an indentation change has been requested), and should look better for proportional fonts.

The following should be an em-space: " "

Here's what Gnome Character Map has to say about it:

U+2003 EM SPACE

General Character Properties

In Unicode since: 1.1
Unicode category: Separator, Space

Various Useful Representations

UTF-8: 0xE2 0x80 0x83
UTF-16: 0x2003

C octal escaped UTF-8: \342\200\203
XML decimal entity: &#8195;

Annotations and Cross References

Alias names:
• mutton

Notes:
• nominally, a space equal to the type size in points
• may scale by the condensation factor of a font

Approximate equivalents:
• U+0020 SPACE space

Ummm, I just took a look at the other Unicode spaces, and em-space may not be best (though it is suitable). Take a look at figure-space (0x2007):

U+2007 FIGURE SPACE

General Character Properties

In Unicode since: 1.1
Unicode category: Separator, Space

Various Useful Representations

UTF-8: 0xE2 0x80 0x87
UTF-16: 0x2007

C octal escaped UTF-8: \342\200\207
XML decimal entity: &#8199;

Annotations and Cross References

Notes:
• space equal to tabular width of a font
• this is equivalent to the digit width of fonts with fixed-width digits

Approximate equivalents:
• U+0020 SPACE

Notice that the figure-space width is rigidly specified, where it is "nominal" for em-space. By definition, this means it is precisely equivalent to a regular space (0x20) in fixed-width fonts.

Both figure-space and em-space should be well understood in an indentation context.

For completeness, let's look at tab (HT, 0x09):

U+0009 <control>

General Character Properties

In Unicode since: 1.1
Unicode category: Other, Control

Various Useful Representations

UTF-8: 0x09
UTF-16: 0x0009

C octal escaped UTF-8: \011
XML decimal entity: &#9;

Annotations and Cross References

Alias names:
• CHARACTER TABULATION
• horizontal tabulation (HT), tab

No width is mentioned, so since it has no glyph I believe that means it is up to the display system (presumably relative to "tab stops"). Is there any standard that states the displayed width of a tab or the positioning of tab stops? I don't think so!

> The "right" solution is to use (have!) editors that handle tabs like
> (flexible) "tab stops" and thus that show code nicely even if a
> proportional font is used (which I personally find desirable, too).

No, that seems impractical: Tab interpretation has been hacked to death for decades. I'd prefer to completely avoid using the tab character for indentation, since its interpretation by programmers and editors and *printers* is ambiguous. Globally replace all tab instances with "FUBAR".

For now, for minimal uniformity, gofmt could enforce a default tab stop at multiples 8 em-spaces/figure-spaces. I don't know if this would help when printing code files as text.

I would not be against gofmt embedding a special comment that reflects the tab stop settings and indentation character used. This comment, if present (as, say, the second line in a file), would be read by subsequent gofmt runs, overridden by command line parameters, then rewritten in the output. If we could get editors to understand it too, then our work would be done... I suspect something like this must already exist!

Still, I'd very much prefer to avoid tabs altogether. Everywhere I've worked, the coding style guide outlaws tabs for indentation. Expect this to be the norm when/if Go is used in commercial contexts and/or for projects with many contributors.

> I am experimenting with a version that uses tabs for indentation only,
> and blanks (or what-have-you) elsewhere. For various reasons, aligned
> columns are broken across sections of different indentation; thus all
> code at a given tab width is uniformly indented proportional to the tab
> width and (at least using a fixed-width font), everything else in the
> respective section remains aligned independent of tab width.
>
> Still not ideal for proportional fonts but it allows users to set the
> tab width to their liking and the code looks reasonable (without the
> need to re-apply gofmt). It also prevents the rather large gaps between
> columns.

Leading em-spaces/figure-spaces can do all this with greater simplicity and reliability for both printers and editors.

> We are aware that the gofmt output may not be to everybody's liking but
> we much prefer having a uniform and fairly reasonable style over a
> variety of different styles.

Uh, well, since you already have a "variety of different styles"...

Let's try adding one that is unambiguous and looks good with all Unicode fonts, with all Unicode-capable editors and printers, and see if it catches on.

After all, isn't one of Go's selling points that it has better Unicode-awareness? Why continue to play "Hack-the-Tab"?

The underlying issue is really more about consistently obtaining the desired presentation of formatted source code while retaining syntactic code indentation (not that it applies to Go, but does to Python). Tabs can have different meanings to different programs (editors, compilers, formatters, etc.) and printers. Em-space and figure-space are far more consistent.


-BobC
> <mailto:yuk...@gmail.com><yuk...@gmail.com
> <mailto:baldmo...@gmail.com>>
>
>
>
> On Nov 30, 12:44 pm, Weeble<clockworksa...@gmail.com
> <mailto:clockworksa...@gmail.com>> wrote:
>
> On Nov 30, 4:52 pm, Ben Tilly<bti...@gmail.com

Tor Andersson

unread,
Dec 2, 2009, 11:13:42 AM12/2/09
to golang-nuts
On Wed, Dec 2, 2009 at 5:21 AM, Bob Cunningham <Fly...@gmail.com> wrote:

[snip]

> Leading em-spaces/figure-spaces can do all this with greater simplicity and
> reliability for both printers and editors.

I fail to see how using em-spaces will help solve anything. I'm willing to bet
that 90% of editors will barf on the unicode characters (and break all movement
commands like next-word, next-sentence) and make it impossible to use grep and
sed on the files. And worse: it still doesn't solve the problem of aligning
stuff when using proportional fonts.

Using tabs for indentation has one major benefit: it lets people use whatever
size indentation they care for and can still work on the same file.
Just set your
tabs to be 2, 4, or 8 spaces wide or how you prefer and get on with it.

Just stop trying to pretty format and align comments and types or anything
past the initial indent. There is no one solution that will work for everyone's
editor.

If you want fancy layouts use a page layout program -- not plain text.

I love everything else about gofmt and I wholeheartedly support the
ideas behind it. If only the results were usable with proportional fonts
and tabs that are not eight spaces wide.

-tor

Robert Griesemer

unread,
Dec 2, 2009, 8:16:39 PM12/2/09
to Tor Andersson, golang-nuts
FYI:

A new version of gofmt that supports indentation with tabs but does any other alignment with spaces has been submitted (revision: 17d3ac883e). It will allow users to set the tab width to their liking w/o affecting the alignment of the rest of the code (aligned columns are broken when indentation changes (for independent reasons), and thus a block of equally indented code will simply move proportionally with the tab width).

This provides the benefits of the tabs for indentation, but doesn't require re-gofmt'ing just because one changed the editor's tab width.

It's still not great for proportional width fonts (maybe worse because using tabs everywhere lead to incidental alignment).

The default setting for gofmt has not changed as we may want to fine-tune the new mode a bit before deciding whether it should become the new default.

To try the new mode: gofmt -tabindent -spaces <files> .

- gri 

PS: The gofmt documenation update is pending.

yuk...@gmail.com

unread,
Dec 3, 2009, 11:25:32 AM12/3/09
to Robert Griesemer, Tor Andersson, golang-nuts
Cool!

Now people can have their own tab settings and the appearance will still be correct.

Now we can move forward to the disappearing semicolons :q - should I open an issue for this?

-yuku

Robert Griesemer

unread,
Dec 3, 2009, 12:08:33 PM12/3/09
to yuk...@gmail.com, Tor Andersson, golang-nuts
On Thu, Dec 3, 2009 at 8:25 AM, yuk...@gmail.com <yuk...@gmail.com> wrote:
Cool!

Now people can have their own tab settings and the appearance will still be correct.

Now we can move forward to the disappearing semicolons :q - should I open an issue for this? 

We are re-evaluating the use of semicolons in gofmt and opening an issue is not going to accelerate the process.
- gri 

Robert Griesemer

unread,
Dec 3, 2009, 12:21:01 PM12/3/09
to yuk...@gmail.com, golang-nuts
On Sun, Nov 29, 2009 at 10:39 PM, yuk...@gmail.com <yuk...@gmail.com> wrote:
I'm pretty new to gofmt, I heard that all the source files for the packages are gofmted, so I tried to pass through gofmt my source files and I was very surprised with the result!?

I got this:

const (
_ PrintMode = iota;
PRINT_PT; // for point print
PRINT_NT; // for node type print
)

1. Why so many tabs for this const declarations? It was just as simple as

const (
_ PrintMode = iota;
PRINT_PT; // for point print
PRINT_NT; // for node type print
PRINT_BO; // for both NT(PT)
)


This should look better now with gofmt -spaces -tabindent settings. 


Then, for imports, I got this:

import (
"rand";
"fmt";  <-- note that semicolon is still intact
)

But

if i == 0 && y == j {
y--  <-- semicolon removed
} else if j == 0 && x == i {
x--  <-- semicolon removed
}

2. Why is semicolon removed on the program statements, but not on the import statements?

The rule used is simple: A single-statement statement list doesn't get a semicolon at the end. All other lists get a trailing optional semicolon if the closing ) or } is on a new line. We are revisiting this.


Then on variable declarations

type Player struct {
name string; <-- two tabs between "name" and "string"
num_moves int;  <-- one tab between "num_moves" and "int"
position Point; <-- one tab
}


3. Why does gofmt put tabs between names of fields and their types? Moreover, some had 2 tabs and some had 1 tab. 
How if the viewer does not use a fixed tab size, doesn't it make the source look uglier?

To make this look correctly, the tab width needs to be set to 8. Again, using the new gofmt setting: -spaces -tabindent will solve this.


func (this *Player) SetName(name string) { this.name = name }

4. A tab between function prototype and the body, and the body is made on the same line? 
I don't get it why newlines are removed in this case.

"Short" functions (for some definition of short) are written as "one-liners". 


if (i != 0 || j != 0) && rand.Int()%RAND_FACT == 0 ... 

5. Before gofmt, there is a space before and after "%". Why does it remove the spaces around %, but not around +, *, && and other operators?

Placement of spaces around expressions is complicated. Ideally, we want "more space" around operators with weak precedence and "less space" around operators with stronger precedence to visually emphasize the binding strength: For example:

x + a*b - c*d

looks better than

x+a*b-c*d

or

x + a * b - c * d

Making this look good in general is not entirely trivial and a work in progress. This may improve over time but at the same time we don't want to change formatting every few weeks.




Personally I pretty much disappointed with those points, may someone help me understand the rationales behind them. I'm sure there are great reasons from the gofmt creators.


Understood. gofmt is a work in progress. It will get better over time. 

-yuku


Esko Luontola

unread,
Dec 3, 2009, 2:23:25 PM12/3/09
to golang-nuts
On Dec 3, 7:21 pm, Robert Griesemer <g...@golang.org> wrote:
> "Short" functions (for some definition of short) are written as
> "one-liners".

I think that it's problematic when gofmt automatically changes a multi-
line function to a one-liner or the other way around.

Here are two examples: http://pastebin.com/f692f4449

In the first example it would be nicer if the formatter would not
inline those short func() blocks. This is a DSL for writing tests, and
it would be better if the code blocks would always be multi-line,
unless the programmer originally writes them as one-liners. In Go,
even the 'if' blocks are always multi-line, and from the programmer's
point of view those nested func() blocks are semantically similar -
they are some sort of control structures, not functions.

In the second example there are three semantically related methods.
Before formatting they are nicely aligned one-liners, so that it's
immediately clear that they belong together and what is the difference
between them. After formatting the first method is multi-lined and the
methods don't anymore line up nicely. In this case it would be nice if
gofmt would not change one-liners to multi-liners automatically, and
it would also detect when the starting '{' of the method blocks are
aligned, and it would keep them aligned even after formatting
(changing the indent would be allowed).

Russ Cox

unread,
Dec 3, 2009, 2:52:10 PM12/3/09
to Esko Luontola, golang-nuts
If gofmt preserved all these details (like brace style),
then we would be arguing about which you should use,
just like in C. Gofmt regularizes the source code precisely
to avoid this kind of thing.

http://groups.google.com/group/golang-nuts/t/1c2dac0e1ad95b96#1913cbd6c58a2bee

atomly

unread,
Dec 3, 2009, 2:57:04 PM12/3/09
to r...@golang.org, Esko Luontola, golang-nuts
Thank you.

Please don't add exceptions to gofmt. Please.

gofmt produces code that doesn't look anything like I prefer, but at
least it's a standard.
--
:: atomly ::

[ ato...@atomly.com : www.atomly.com : http://blog.atomly.com/ ...
[ atomiq records : new york city : +1.917.442.9450 ...
[ e-mail atomly-new...@atomly.com for atomly info and updates ...

Esko Luontola

unread,
Dec 3, 2009, 8:03:29 PM12/3/09
to golang-nuts
The important question to as is that does the code communicate the
programmer's intent. Or as Kent Beck puts it, "how would someone else
see this?" [1]

Especially in my latter example, the original code communicated well
that the three methods are closely related, because they follow the
gestalt laws of similarity and proximity [2]. After formatting, it
communicates that only the last two are closely related.

gofmt already does some things where it maintains some of the
whitespace formatting from the original writer, because that helps the
code to communicate better that which parts belong together. For
example empty lines are kept in place, because programmers use empty
lines to separate unrelated parts and to group related parts.

But the case of one-liners, gofmt does not pay attention to
communication. Instead, it follows only syntax - how many characters
are on a line.

In Effective Go it has been stated that if gofmt does something which
doesn't seem right, then it's best to fix the program. So the question
remains, which of the code communicates better - the one before or
after gofmt? If gofmt lowers the readability, then it's better to
improve gofmt instead of not using it.

[1] Implementation Patterns, page 11.
[2] http://en.wikipedia.org/wiki/Gestalt_psychology#Pr.C3.A4gnanz


On Dec 3, 9:52 pm, Russ Cox <r...@golang.org> wrote:
> If gofmt preserved all these details (like brace style),
> then we would be arguing about which you should use,
> just like in C.  Gofmt regularizes the source code precisely
> to avoid this kind of thing.
>
> http://groups.google.com/group/golang-nuts/t/1c2dac0e1ad95b96#1913cbd...

Tor Andersson

unread,
Dec 3, 2009, 9:26:35 PM12/3/09
to Robert Griesemer, yuk...@gmail.com, golang-nuts
On Thu, Dec 3, 2009 at 6:21 PM, Robert Griesemer <g...@golang.org> wrote:
> On Sun, Nov 29, 2009 at 10:39 PM, yuk...@gmail.com <yuk...@gmail.com> wrote:
>> 3. Why does gofmt put tabs between names of fields and their types?
>> Moreover, some had 2 tabs and some had 1 tab.
>> How if the viewer does not use a fixed tab size, doesn't it make the
>> source look uglier?
>
> To make this look correctly, the tab width needs to be set to 8. Again,
> using the new gofmt setting: -spaces -tabindent will solve this.

I'm going to start sounding like a broken record soon -- but -- it still
doesn't work for this obstinate proportional font user. Unless you mean
using the new gofmt setting followed by |sed 's/ */ /g' ;)

> "Short" functions (for some definition of short) are written as
> "one-liners".

> Placement of spaces around expressions is complicated. Ideally, we want
> "more space" around operators with weak precedence and "less space" around
> operators with stronger precedence to visually emphasize the binding
> strength: For example:
> x + a*b - c*d
> looks better than
> x+a*b-c*d
> or
> x + a * b - c * d

Mmm. I believe in regularity here. "x + a*x - c*d" may look better than
"x + a * b - c * d" but "x && rand.Int()%RAND_FACT" sure doesn't. All this
proves is that the smart rules will never get every case right, whereas the
simple regular rule of "x + a * b" will always be good enough. It's also
predictable, so I can write code that complies without even using gofmt.

Likewise with the short one-line functions... now we have two different looks
for a function, and which you will get depends. Again I'll argue for
regularity --
all it costs is two lines! Not to mention that editing a one liner to become
a multi line function is far more work if it's all on one line that
has to be broken
up and indented.

Please take this plea for regularity and predictability in consideration.

Regards,
Tor

Russ Cox

unread,
Dec 3, 2009, 9:52:35 PM12/3/09
to Tor Andersson, golang-nuts
> I'm going to start sounding like a broken record soon -- but -- it still
> doesn't work for this obstinate proportional font user. Unless you mean
> using the new gofmt setting followed by |sed 's/  */ /g' ;)

Sure, you can do that. Two of us (Rob and I) use proportional
fonts almost exclusively, and we feel your pain, but we also
understand that we are a very small minority. It's more
important to have something that works well for the
other 99% of the programmers, people browsing sources
on the web, and so on.

> simple regular rule of "x + a * b" will always be good enough. It's also
> predictable, so I can write code that complies without even using gofmt.

We like regularity too, but we like readability more,
and the few breaks from regularity in gofmt are for
things that we felt, after over a year of writing
Go programs, enhanced readability enough to justify
breaking from the simpler rules.

In this specific case, 1<<x + y is much clearer as
to its meaning than 1 << x + y, because it emphasizes
the precedence.

Your example - "x && rand.Int()%RAND_FACT" - is not
the whole story: you lifted a fragment. The real expression
would have been something like

x && rand.Int()%RAND_FACT != 0

since a % cannot produce a bool and && requires one.
If the op were & instead of %, like in

x && rand.Int()&RAND_MASK != 0

then I appreciate the visual reinforcement that it's being
parsed the way I intend (i.e. it has a different meaning
here than it would in C).

Especially because operator precedence is a notorious
source of confusion in C and because Go changed
the precedences to simplify things, we think this is an
important way to help programmers adjust.

Yes, one can construct complex expressions that are
formatted worse than you could do with hand-tweaking,
but we judged that the win in this case was worth
breaking with the simplicity of "spaces everywhere".
It wasn't something we did lightly, and we understand
we can't please everyone.

Russ

Bob Cunningham

unread,
Dec 4, 2009, 3:35:24 AM12/4/09
to golang-nuts
On 12/03/2009 06:52 PM, Russ Cox wrote:
>> I'm going to start sounding like a broken record soon -- but -- it still
>> doesn't work for this obstinate proportional font user. Unless you mean
>> using the new gofmt setting followed by |sed 's/ */ /g' ;)
>
> Sure, you can do that. Two of us (Rob and I) use proportional
> fonts almost exclusively, and we feel your pain, but we also
> understand that we are a very small minority. It's more
> important to have something that works well for the
> other 99% of the programmers, people browsing sources
> on the web, and so on.

Well, that's fine, but being the first to intrinsically support proportional fonts may be a Good Thing, especially when combined with Go's deep Unicode support. I suspect there are solutions that will work well for both domains (em-space).

Break out of the ASCII box!

>> simple regular rule of "x + a * b" will always be good enough. It's also
>> predictable, so I can write code that complies without even using gofmt.
>
> We like regularity too, but we like readability more,
> and the few breaks from regularity in gofmt are for
> things that we felt, after over a year of writing
> Go programs, enhanced readability enough to justify
> breaking from the simpler rules.
>
> In this specific case, 1<<x + y is much clearer as
> to its meaning than 1<< x + y, because it emphasizes
> the precedence.
>
> Your example - "x&& rand.Int()%RAND_FACT" - is not
> the whole story: you lifted a fragment. The real expression
> would have been something like
>
> x&& rand.Int()%RAND_FACT != 0
>
> since a % cannot produce a bool and&& requires one.
> If the op were& instead of %, like in
>
> x&& rand.Int()&RAND_MASK != 0
>
> then I appreciate the visual reinforcement that it's being
> parsed the way I intend (i.e. it has a different meaning
> here than it would in C).
>
> Especially because operator precedence is a notorious
> source of confusion in C and because Go changed
> the precedences to simplify things, we think this is an
> important way to help programmers adjust.
>
> Yes, one can construct complex expressions that are
> formatted worse than you could do with hand-tweaking,
> but we judged that the win in this case was worth
> breaking with the simplicity of "spaces everywhere".
> It wasn't something we did lightly, and we understand
> we can't please everyone.

Bah! Humbug! ('Tis the Season, don't ya' know.) Using an incomplete space-based heuristic to denote relative operator precedence seems penny-wise and pound-foolish to me.

Add a gofmt option that imposes full expression parenthesization (if that's a word) for multi-operation expressions, so that the reader has no need to risk any confusion concerning operator precedence. (No need to pull out the Go spec, or to stare at spaces as if they were goats.)

At a prior employer, where I developed avionics software in C, we were required to use parentheses around all infix operator sub-expressions, the only exception being for repeated operations, e.g. (a + b + c + d) or (a * b * c * d). We didn't even allow (a + b - c + d). It wasn't because we didn't trust the compiler: We didn't trust the programmer, and with very good reason.

In one particular case I recall, we had a set of very complex math/logic equations to determine when to (and not to) generate a terrain avoidance alert when on final approach to landing (where the ground is expected to get closer, we know where the runway is, we know where the terrain and all obstacles are, and we know where the aircraft is and will likely be in the near future).

There were many parameters, and the code was very carefully crafted. It passed our rigorous in-house testing, but had errors on our test flights (both false positive and false negative errors). We repeatedly reviewed the code line-by-line, and nobody saw any problem. It wasn't until we examined detailed execution traces (which are both a PITA and very expensive to acquire on a jet aircraft during a landing) that a single operator precedence goof became evident. The added costs and delays made this literally a $250,000 bug.

Adding a "fullparen" option to gofmt would be useful for similar safety-critical applications. It would let the programmer clearly see how the compiler intends to interpret each expression. The presence of all those parens affects readability less than you would imagine, since expressions that grow too large due to added parens generally are in dire need of refactoring and/or simplification.

It would be far worse, and totally unacceptable, if gofmt ever *removed* "extraneous" parens in expressions, and replaced them with (or without) spaces! I haven't tested this yet: Does gofmt do anything like this?


-BobC

yy

unread,
Dec 4, 2009, 4:03:41 AM12/4/09
to r...@golang.org, Tor Andersson, golang-nuts
2009/12/4 Russ Cox <r...@golang.org>:
>> I'm going to start sounding like a broken record soon -- but -- it still
>> doesn't work for this obstinate proportional font user. Unless you mean
>> using the new gofmt setting followed by |sed 's/  */ /g' ;)
>
> Sure, you can do that.  Two of us (Rob and I) use proportional
> fonts almost exclusively, and we feel your pain, but we also
> understand that we are a very small minority.  It's more
> important to have something that works well for the
> other 99% of the programmers, people browsing sources
> on the web, and so on.
>

We could even be more than that 1% :)

Personally, I find gofmt a great thing too. I always preferred sane
defaults to customization and at the end of the day not having to
think about coding style gives me more freedom (ironic?), but I feel
the pain in acme. Would it be possible to include in the distribution
a couple of very simple sed or awk scripts (or whatever) to do the
translation to gofmt format? What I want is to have in my tag bar
something like: Edit ,|gofmt|go2varfont and |varfont2go. I know this
will be at the bottom of the todo list, and I already have my personal
scripts which more or less work (yes, it is trivial), but it would be
fine to have some kind of standard formatting for variable width
fonts, and I thought you could already have something for personal use
which could be shared, before all we start to write our own tools
(this is dangerous, they could become preprocessors...)

PS: it would be fine if gofmt limited its line width to some high
value, eg: http://hg.4l77.com/go/ngaro/file/tip/image.go#l10
I will open an issue about this, but would prefer to send a patch,
though it won't be very soon, sorry.

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

Bob Cunningham

unread,
Dec 4, 2009, 2:24:39 PM12/4/09
to Rob 'Commander' Pike, golang-nuts
On 12/04/2009 07:59 AM, Rob 'Commander' Pike wrote:
>
> On Dec 4, 2009, at 12:35 AM, Bob Cunningham wrote:
>
>> Well, that's fine, but being the first to intrinsically support proportional fonts may be a Good Thing, especially when combined with Go's deep Unicode support. I suspect there are solutions that will work well for both domains (em-space).
>
> The problem is you need to know the font details to do this right, and gofmt is intended for sharing and publishing and can't know the reader's font in advance. It's not easy to know what to do.
>
> Plain text is just that.

Which font details?

Let's clarify the context a bit:
1. We're not talking about ASCII. This is a Unicode-only discussion, and all UTF8 space characters are available.
2. We're using an editor that supports the entering and display of Unicode, UTF8 in particular.
3. We're using primarily the Latin characters from whichever font is selected, with other characters (e.g. Greek, Hebrew) used much less often.
4. We're talking only about start-of-line indentation, which is present in every Go file. Multiple columns are a more complex, but far less common, matter that require some form of explicit column definition, either by tab-stops or other means that are TBD.

The Unicode "figure-space" character is specified to have PRECISELY defined width in ALL Unicode fonts. The "em-space" character has the same width by convention, but not by specification.

Can you describe a situation where indenting the start of a line using figure-space could possibly, ever, produce a non-uniform indentation result when bouncing a given text between any number of proportional and fixed fonts?

As a final step, use cat to dump a file using any of the indentation styles you prefer to a UTF8-aware printer (or process using some other page renderer, such as txt2pdf) that has been configured with an *unknown* default font. Which indentation styles will "just work" in this simple situation? This is one place where indentation using figure-space shines.

I can't conceive of a single "bad" situation, but perhaps that's due only to a low brain-cell count.

At worst, the editor would need a simple rule: "All whitespace entered at the beginning of a line shall be instantiated using figure-space." This behavior could be supplied by gofmt initially, and many editors are easily configurable to support it now.

As for columns, you're in a mess anyway, since that's a higher level of layout than leading indentation, one which is highly font-dependent. I'd prefer to see a language that explicitly understands some minimal convention for font-independent column layout (HTML, BBtext, whatever), rather than keep hacking away at the tabulation dead-horse (which will *always* have font-dependent failure modes).

Perhaps we should instead permit Go source code to be entered using an HTML editor, and the Go compilers should be smart enough to strip the markup. IIRC, there are some languages that already do this. What gofmt would/could/should do in this context is a very open issue.

-BobC
Reply all
Reply to author
Forward
0 new messages