How to break a long line of code in Golang? - go

Coming from Python, I'm not used to see code lines longer than 80 columns.
So when I encounter this:
err := database.QueryRow("select * from users where user_id=?", id).Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)
I tried to break it to
err := database.QueryRow("select * from users where user_id=?", id) \
.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)
But I get
syntax error: unexpected \
I also tried just breaking the line with hitting enter and put a semicolon at the end:
err := database.QueryRow("select * from users where user_id=?", id)
.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email);
But the I again get:
syntax error: unexpected .
So I'm wondering what's the golangic way to do so?

First some background. The formal grammar of Go uses semicolons ";" as terminators in many productions, but Go programs may omit most of them (and they should to have a clearer, easily readable source; gofmt also removes unnecessary semicolons).
The specification lists the exact rules. Spec: Semicolons:
The formal grammar uses semicolons ";" as terminators in a number of productions. Go programs may omit most of these semicolons using the following two rules:
When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is
an identifier
an integer, floating-point, imaginary, rune, or string literal
one of the keywords break, continue, fallthrough, or return
one of the operators and delimiters ++, --, ), ], or }
To allow complex statements to occupy a single line, a semicolon may be omitted before a closing ")" or "}".
So as you can see if you insert a newline character after the parenthesis ), a semicolon ; will be inserted automatically and so the next line will not be treated as the continuation of the previous line. This is what happened in your case, and so the next line starting with .Scan(&ReadUser.ID,... will give you a compile-time error as this standing by itself (without the previous line) is a compile-time error: syntax error: unexpected .
So you may break your line at any point which does not conflict with the rules listed under point 1. above.
Typically you can break your lines after comma ,, after opening parenthesis e.g. (, [, {, and after a dot . which may be referencing a field or method of some value. You can also break your line after binary operators (those that require 2 operands), e.g.:
i := 1 +
2
fmt.Println(i) // Prints 3
One thing worth noting here is that if you have a struct or slice or map literal listing the initial values, and you want to break line after listing the last value, you have to put a mandatory comma , even though this is the last value and no more will follow, e.g.:
s := []int {
1, 2, 3,
4, 5, 6, // Note it ends with a comma
}
This is to conform with the semicolon rules, and also so that you can rearrange and add new lines without having to take care of adding / removing the final comma; e.g. you can simply swap the 2 lines without having to remove and to add a new comma:
s := []int {
4, 5, 6,
1, 2, 3,
}
The same applies when listing arguments to a function call:
fmt.Println("first",
"second",
"third", // Note it ends with a comma
)

The simplest way is to simply leave the operator (.) on the first line.
\ line continuations are also discouraged in many python style guides, you could wrap the whole expression in parens if you are moving back and forth between go and python as this technique works in both languages.

As mentioned, this is a matter of style preference. I understand that the creators of Go have suggested a style based on their experience of which I learn from but also keep some of my own style from my experience.
Below is how I would format this:
err := database.
QueryRow("select * from users where user_id=?", id).
Scan(
&ReadUser.ID,
&ReadUser.Name,
&ReadUser.First,
&ReadUser.Last,
&ReadUser.Email,
)

It's a matter of style, but I like:
err := database.QueryRow(
"select * from users where user_id=?", id,
).Scan(
&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email,
)

what's the golangic way to do so?
An automated solution. Unfortunately, gofmt doesn't cover this case so you could use
https://github.com/segmentio/golines
Install it via
go install github.com/segmentio/golines#latest
Then run
golines -w -m 80 .
-w means make the changes in-place (default prints to stdout)
-m is max column length

You can break the line at several places like commas or braces as suggested by other answers. But Go community has this opinion on line length:
There is no fixed line length for Go source code. If a line feels too long, it should be refactored instead of broken.
There are several guidelines there in the styling guide. I am adding some of the notable ones (clipped):
Commentary
Ensure that commentary is readable from source even on narrow screens.
...
When possible, aim for comments that will read well on an 80-column wide terminal, however this is not a hard cut-off; there is no fixed line length limit for comments in Go.
Indentation confusion
Avoid introducing a line break if it would align the rest of the line with an indented code block. If this is unavoidable, leave a space to separate the code in the block from the wrapped line.
// Bad:
if longCondition1 && longCondition2 &&
// Conditions 3 and 4 have the same indentation as the code within the if.
longCondition3 && longCondition4 {
log.Info("all conditions met")
}
Function formatting
The signature of a function or method declaration should remain on a single line to avoid indentation confusion.
Function argument lists can make some of the longest lines in a Go source file. However, they precede a change in indentation, and therefore it is difficult to break the line in a way that does not make subsequent lines look like part of the function body in a confusing way:
// Bad:
func (r *SomeType) SomeLongFunctionName(foo1, foo2, foo3 string,
foo4, foo5, foo6 int) {
foo7 := bar(foo1)
// ...
}
// Good:
good := foo.Call(long, CallOptions{
Names: list,
Of: of,
The: parameters,
Func: all,
Args: on,
Now: separate,
Visible: lines,
})
// Bad:
bad := foo.Call(
long,
list,
of,
parameters,
all,
on,
separate,
lines,
)
Lines can often be shortened by factoring out local variables.
// Good:
local := helper(some, parameters, here)
good := foo.Call(list, of, parameters, local)
Similarly, function and method calls should not be separated based solely on line length.
// Good:
good := foo.Call(long, list, of, parameters, all, on, one, line)
// Bad:
bad := foo.Call(long, list, of, parameters,
with, arbitrary, line, breaks)
Conditionals and loops
An if statement should not be line broken; multi-line if clauses can lead to indentation confusion.
// Bad:
// The second if statement is aligned with the code within the if block, causing
// indentation confusion.
if db.CurrentStatusIs(db.InTransaction) &&
db.ValuesEqual(db.TransactionKey(), row.Key()) {
return db.Errorf(db.TransactionError, "query failed: row (%v): key does not match transaction key", row)
}
If the short-circuit behavior is not required, the boolean operands can be extracted directly:
// Good:
inTransaction := db.CurrentStatusIs(db.InTransaction)
keysMatch := db.ValuesEqual(db.TransactionKey(), row.Key())
if inTransaction && keysMatch {
return db.Error(db.TransactionError, "query failed: row (%v): key does not match transaction key", row)
}
There may also be other locals that can be extracted, especially if the conditional is already repetitive:
// Good:
uid := user.GetUniqueUserID()
if db.UserIsAdmin(uid) || db.UserHasPermission(uid, perms.ViewServerConfig) || db.UserHasPermission(uid, perms.CreateGroup) {
// ...
}
// Bad:
if db.UserIsAdmin(user.GetUniqueUserID()) || db.UserHasPermission(user.GetUniqueUserID(), perms.ViewServerConfig) || db.UserHasPermission(user.GetUniqueUserID(), perms.CreateGroup) {
// ...
}
switch and case statements should also remain on a single line.
// Good:
switch good := db.TransactionStatus(); good {
case db.TransactionStarting, db.TransactionActive, db.TransactionWaiting:
// ...
case db.TransactionCommitted, db.NoTransaction:
// ...
default:
// ...
}
// Bad:
switch bad := db.TransactionStatus(); bad {
case db.TransactionStarting,
db.TransactionActive,
db.TransactionWaiting:
// ...
case db.TransactionCommitted,
db.NoTransaction:
// ...
default:
// ...
}
If the line is excessively long, indent all cases and separate them with a blank line to avoid indentation confusion:
// Good:
switch db.TransactionStatus() {
case
db.TransactionStarting,
db.TransactionActive,
db.TransactionWaiting,
db.TransactionCommitted:
// ...
case db.NoTransaction:
// ...
default:
// ...
}
Never brake long URLs into multiple lines.
I have only added some of the few examples there are in the styling guide. Please read the guide to get more information.

Related

Why is there a comma in this Golang struct creation?

I have a struct:
type nameSorter struct {
names []Name
by func(s1, s2 *Name) bool
Which is used in this method. What is going on with that comma? If I remove it there is a syntax error.
func (by By) Sort(names []Name) {
sorter := &nameSorter{
names: names,
by: by, //why does there have to be a comma here?
}
sort.Sort(sorter)
Also, the code below works perfectly fine and seems to be more clear.
func (by By) Sort(names []Name) {
sorter := &nameSorter{names, by}
sort.Sort(sorter)
For more context this code is part of a series of declarations for sorting of a custom type that looks like this:
By(lastNameSort).Sort(Names)
This is how go works, and go is strict with things like comma and parentheses.
The good thing about this notion is that when adding or deleting a line, it does not affect other line. Suppose the last comma can be omitted, if you want to add a field after it, you have to add the comma back.
See this post: https://dave.cheney.net/2014/10/04/that-trailing-comma.
From https://golang.org/doc/effective_go.html#semicolons:
the lexer uses a simple rule to insert semicolons automatically as it scans, so the input text is mostly free of them
In other words, the programmer is unburdened from using semicolons, but Go still uses them under the hood, prior to compilation.
Semicolons are inserted after the:
last token before a newline is an identifier (which includes words like int and float64), a basic literal such as a number or string constant, or one of the tokens break continue fallthrough return ++ -- ) }
Thus, without a comma, the lexer would insert a semicolon and cause a syntax error:
&nameSorter{
names: names,
by: by; // semicolon inserted after identifier, syntax error due to unclosed braces
}

Strange behavior when appending to a 2d slice

I am using a 2D slice of bytes to represent a bunch of lines, but when I append to one of the lines, I get some very strange behavior.
Here is an example:
package main
import (
"bytes"
"fmt"
)
func main() {
str := []byte("first line\nsecond line\nthird line")
values := bytes.Split(str, []byte("\n"))
fmt.Println("Before:")
fmt.Println(string(values[0]))
fmt.Println(string(values[1]))
fmt.Println(string(values[2]))
fmt.Println()
values[0] = append(values[0], []byte("-inserted text-")...)
fmt.Println("After:")
fmt.Println(string(values[0]))
fmt.Println(string(values[1]))
fmt.Println(string(values[2]))
}
I would expect the output of this program to be
Before:
first line
second line
third line
After:
first line-inserted text-
second line
third line
But instead the output is:
Before:
first line
second line
third line
After:
first line-inserted text-
inserted te
t-ird line
https://play.golang.org/p/iNw6s1S66U
Why is this happening and how can I fix it?
Interestingly, this doesn't happen if I don't use split and instead define values like so:
values := [][]byte{[]byte("first line"), []byte("second line"), []byte("third line")}
https://play.golang.org/p/pEflrhKLd4
The underlying storage is shared, so to get the effect you want, you would need to store copies of the slices returned from bytes.Split, rather than just the slices returned. When you append to the first slice returned, you're essentially stomping all over the following slices.
What you're doing is appending to the string, instead of appending to the array and thats overflowing the underlying data structure for the slice. Which is why the rest of the array is overwritten with the string you're appending.
To clarify (this may not always be the case):
the array values consists of 3 []byte blocks lined up consecutively. Each []byte block has a fixed length (based on the length of the string within it). So values[0] has a length of 10 (excluding '\n' or '\0'). Now if you try to append "-inserted text-" to that block, the characters will "flow" over into the consecutive block, values[1], replacing the characters within values[1] with the characters in "-inserted text-". That's why you see parts of those characters within values[1] and values[1].

How to print comments in lex?

So the title might be a little bit misleading, but I can't think of any better way to phrase it.
Basically, I'm writing a lexical-scanner using cygwin/lex. A part of the code reads a token /* . It the goes into a predefined state C_COMMENT, and ends when C_COMMENT"/*". Below is the actual code
"/*" {BEGIN(C_COMMENT); printf("%d: /*", linenum++);}
<C_COMMENT>"*/" { BEGIN(INITIAL); printf("*/\n"); }
<C_COMMENT>. {printf("%s",yytext);}
The code works when the comment is in a single line, such as
/* * Example of comment */
It will print the current line number, with the comment behind. But it doesn't work if the comment spans multiple lines. Rewriting the 3rd line into
<C_COMMENT>. {printf("%s",yytext);
printf("\n");}
doesn't work. It will result in \n printed for every letter in the comment. I'm guessing it has something to do with C having no strings or maybe I'm using the states wrong.
Hope someone will be able to help me out :)
Also if there's any other info you need, just ask, and I'll provide.
The easiest way to echo the token scanned by a pattern is to use the special action ECHO:
"/*" { printf("%d: ", linenum++); ECHO; BEGIN(C_COMMENT); }
<C_COMMENT>"*/" { ECHO; BEGIN(INITIAL); }
<C_COMMENT>. { ECHO; }
None of the above rules matches a newline inside a comment, because in (f)lex . doesn't match newlines:
<C_COMMENT>\n { linenum++; ECHO; }
A faster way of recognizing C comments is with a single regular expression, although it's a little hard to read:
[/][*][^*]*[*]+([^/*][^*][*]+)*[/]
In this case, you'll have to rescan the comment to count newlines, unless you get flex to do the line number counting.
flex scanners maintain a line number count in yylineno, if you request that feature (using %option yylineno). It's often more efficient and always more reliable than keeping the count yourself. However, in the action, the value of yylineno is the line number count at the end of the pattern, not at the beginning, which can be misleading for multiline patterns. A common workaround is to save the value of yylineno in another variable at the beginning of the token scan.

how do you chain commands on several lines in go?

I want to chain commands this way :
var cmdGroups = []*commands.CmdGroup {
commands.MakeCmdGroup("foo", cmd1, cmd2, cmd3).AddConstraint(cmd1, cmd2).AddConstraint(cmd2, cmd1, cmd3),
commands.MakeCmdGroup("bar", cmd1, cmd4).AddConstraint(cmd1, cmd4),
}
I'd like to split my chains on several lines for 80-column-lengths reasons, but Go won't let me compile this :
var cmdGroups = []*commands.CmdGroup {
commands.MakeCmdGroup("foo", cmd1, cmd2, cmd3)
.AddConstraint(cmd1, cmd2)
.AddConstraint(cmd2, cmd1, cmd3),
commands.MakeCmdGroup("bar", cmd1, cmd4)
.AddConstraint(cmd1, cmd4),
}
what can I do ?
As FUZxxl pointed out, your problem is the automatic insertion of semicolons.
The spec says:
When the input is broken into tokens, a semicolon is automatically
inserted into the token stream at the end of a non-blank line if the
line's final token is
an identifier
an integer, floating-point, imaginary, rune, or string
literal
one of the keywords break, continue, fallthrough, or return
one of the operators and delimiters ++, --, ), ], or }
You have a function call, which counts for a ) so a semicolon is added at the end of the line.
To circumvent automatic semicolon conversion you can write your calls in one of the following
ways:
Use the . instead of semicolon:
x.
Method(p1,p2,p3)
Break after beginning of parameter list instead of before the function:
x.Method(
p1,p2,p3, // , at the end is important to prevent semicolon insertion
)
If you dislike the methods above, you can (as of go1.1) treat the methods as first class
citizens and temporarily create shortcuts which might be shorter:
f = x.Method
f(p1,p2,p3).f(p3,p4,p5)
I haven't thought enough
with this example. f(...).f(...) is of course not possible, as the return value of f has no member f.
One would have to reassign f. So you gain nothing from that.
I would probably write some variant of:
var cmdGroups = []*commands.CmdGroup{
commands.MakeCmdGroup(
"foo", cmd1, cmd2, cmd3,
).AddConstraint(
cmd1, cmd2,
).AddConstraint(
cmd2, cmd1, cmd3,
),
commands.MakeCmdGroup(
"bar", cmd1, cmd4,
).AddConstraint(cmd1, cmd4),
}
However, such long selector operator chains are not to be seen in idiomatic code too often. (I consider the standard library an informal guide to idiomatic code). Perhaps there might be some weakness in this code design/structure.

A regular expression that moves opening { braces to a new line, for C/C++/PHP/etc code

This kind of code structure makes, IMHO, code less readable:
int func() {
[...]
}
It's just a matter of taste, but I prefer this one:
int func()
{
[...]
}
So I've trying to make a regular expression to apply in my text editor in order to make code in the first example look like the second one.
I've come up with something like ^([\t]*)([^\t{]*)({.*)$ ( I don't remember exactly if it was like this )
The idea is that when a { is found preceded of non-space characters, most probably the function header or a control structure, then split the line and send the { to the next line, but preserving the indent level (I.E. the same amount of tabs) of the original line.
The last part, about keeping the indent level is what I can't get right.
Any help appreciated.
--
PS: Feel free to disagree with my coding standards but please remember that's not the main subject here.
Here is a first try.
file.cpp:
int main() {
for (;;) {
break;
}
return 0;
}
Using sed -r s/^\(\\s*\)\(.*\)\\{$/\\1\\2\\n\\1{/ file.cpp outputs:
int main()
{
for (;;)
{
break;
}
return 0;
}
Selecting lines with sed
Grab spaces at beginning of line ^\(\\s*\).
Grab everything else except last opening brace \(.*\).
Grab opening brace until end of line \\{$.
Substitution
Put back 1st and 2nd back references \\1\\2.
Insert newline and append again 1st back reference.
Open brace.

Resources