go version
)?go version go1.15.2 linux/amd64
yes
go env
)?GO111MODULE=""
GOARCH="amd64"
GOBIN="/home/rwxrob/.local/go/bin"
GOCACHE="/home/rwxrob/.cache/go-build"
GOENV="/home/rwxrob/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/rwxrob/.local/go/pkg/mod"
GONOPROXY="github.com/rwxrob/*,gitlab.com/rwxrob/*"
GONOSUMDB="github.com/rwxrob/*,gitlab.com/rwxrob/*"
GOOS="linux"
GOPATH="/home/rwxrob/.local/go"
GOPRIVATE="github.com/rwxrob/*,gitlab.com/rwxrob/*"
GOPROXY="direct"
GOROOT="/usr/lib/go-1.15"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.15/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/rwxrob/repos/gitlab.com/rwxrob/wsutil/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build770902979=/tmp/go-build -gno-record-gcc-switches"
func first(ctx context.Context) {
log.Println("starting first")
wg.Add(1)
<-ctx.Done()
log.Println("stopping first")
wg.Done()
}
Something that doesn't stutter. You know, like testing.T
or testing.B
. I'm aware that I can provide an alias for context
package but the root of the problem is that context.Context
unnecessarily obfuscates otherwise clear parameter signatures and pushes some of them beyond 80 character terminal status lines. This is particularly annoying because context is always the first parameter and more code now requires them. In fact, at the current pace it sometimes seems like everything is going to have a ctx
version eventually.
This change would not impact backward compatibility.
func first(ctx context.C) {
log.Println("starting first")
wg.Add(1)
<-ctx.Done()
log.Println("stopping first")
wg.Done()
}
See previous
CC @Sajmani
This is particularly annoying
[...]
will receive the praise of thousands of annoyedcontext
users
[...]
further annoyed when the addition of generics makes signatures even more unreadable.
Setting the proposal aside for a second, I think the tone of the original post is unfortunate as it distracts from the proposed idea. Please rememer to be kind.
That is going to be quite confusing, since there is a "C" (capital C) package already. Saving 5 letters vs confusion does not sound like a good trade-off.
(example code is taken from https://karthikkaranth.me/blog/calling-c-code-from-go/ , mangled a bit )
package main
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "greeter.h"
import "C"
import (
"context"
"fmt"
"os"
"time"
"unsafe"
)
func c_greeter(ctx context.C, goname string) {
name := C.CString(goname)
defer C.free(unsafe.Pointer(name))
year := C.int(2018)
ptr := C.malloc(C.sizeof_char * 1024)
defer C.free(unsafe.Pointer(ptr))
size := C.greet(name, year, (*C.char)(ptr))
b := C.GoBytes(ptr, size)
fmt.Println(string(b))
}
func greeter(names []string) {
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
for _, name := range names {
go c_greeter(ctx, name)
}
<-ctx.Done()
}
func main() {
greeter(os.Args[1:])
}
This is particularly annoying
[...]
will receive the praise of thousands of annoyedcontext
users
[...]
further annoyed when the addition of generics makes signatures even more unreadable.Setting the proposal aside for a second, I think the tone of the original post is unfortunate as it distracts from the proposed idea. Please rememer to be kind.
I'm sorry that you consider statements of fact "unkind." I did not mean them to be. I've removed them.
That said, it is simply a fact that 1000s are already annoyed by the widespread adoption of contexts into the language and the dubious decision not to stick with the "don't stutter" style rules outlined by the original creators in something so significant.
That is going to be quite confusing, since there is a "C" (capital C) package already. Saving 5 letters vs confusion does not sound like a good trade-off.
This is a fair objection, imho. I suppose the question is what is the likelihood that contexts would be mixed with C
package. I imagine that would be common enough to consider alternatives. From where I'm sitting, it seems like much more code containing the now mandatory context.Context
is being created. Since this has been renamed to "alias" that leaves the clarification option open. I personally am thankful for this reminder because I had considered using C
as an alias for context
itself, which would further the confusion you mention. Thank you very much for bringing this up.
I don't think it's difficult to distinguish between C
and context.C
. The only time it would be an issue is if you used dot imports.
context.Context already has a name: Context.
testing has T but does _not_ also have Test.
Introducing an alias will only cause confusion about whether to write Context or C.
This does not seem worthwhile.
I would liketo get a concensus for conventions since we appear to have both long and short names: testing.T
, metadata.MD
, context.Context
, url.URL
. Let me know if a separate ticket would be better.
That being said, we could elect to deprecate the context.Context
name, because it is long, and move people to context.C
, thereby maintaining one primary name.
There is no much sense to add an alias in the context
package 'cause everyone can already make own alias (type C = context.Context
) in any package and use it without any problems. Why it should be in the standard library?
pushes some of them beyond 80 character terminal status lines. This is particularly annoying because context is always the first parameter and more code now requires them.
80 lines is your own choice, isn't ? I don't see any problems with 120 or 140 👀
I believe "stuttering" is a well-established Go stylistic anti-pattern. The fact that any of it exists to any degree in the standard library seems against these standards --- especially in such highly used naming conventions. How the decision to use a long, stuttering name in the first place is no longer relevant. We are now left with a discussion of how to rectify this going forward. I sometimes wonder if some of the core Go library package contributors have even read Effective Go and many of the other standard documents related to this topic. The trend to move away from these established stylist patterns concerns me personally. It's more than just one alias or renaming. Thank you.
I don't think many will agree that unnecessarily complex parameter signatures are a good idea. This is not Rust or Java, after all. That 80 character thing was just an example, and yes people chop up their TMUX terminals to 80 and under a lot, but it is less relevant than the overall tendency for core language contributors to be okay with "stuttering" and then justifying it after it has been done.
This is the kind of thing where I don't really see the downside of and I wish Go could be more accommodating to things that just make a majority of people's lives easier even if it minor and is pure convenience and syntactic sugar.
I would totally be on board with deprecating context.Context
in favor of context.C
but I think an alias is step in the right direction. Given how prevalent context objects are in code now it seems like we could do something to make using them more convenient.
Personally I agree with Russ, I don't think this is a worthwhile change. Having two ways of referring to Context will be confusing. That being said, considering how pervasive context is, it makes me wonder why the package was called context and not ctx
, or the type was called Context
and not C
for instance. But I don't think it should be changed now.
While I strongly agree with Russ that we should avoid churn or diff noise where possible, I'd like to point out that if we deprecate context.Context
in favor of context.C
, we could then leverage go fix
to update people's code all at once. This would still mean a bit of diff noise, but the developer cost would be very reasonable.
why the package was called context and not
ctx
Naming a context variable ctx
actually has been a common and well established practice outside of Go for many years already. In most cases you are likely to refer to context
the package once per a function signature at most (given you did not already alias it at the import to something shorter), but to ctx
the variable once per function body at least. You would like the more often used symbol to be the shorter one.
On the actual topic of the proposal, I'm also for deprecating the long, stuttering context.Context
in favor of context.C
. It was bound to happen sooner or later, and the sooner it happens, the less code will have to be go fix
ed.
Based on the discussion above, this seems like a likely decline.
For what it's worth, testing.T was an exception to the usual rule of avoiding abbreviations. For example for Go 1 we fixed up a bunch of names in strconv to have meaningful ones like ParseInt and so on, although we did keep Atoi for historical reasons.
Part of the justification for testing.T was that it is so much a part of the boilerplate of _every_ test, and we were trying to make tests super lightweight, so we broke the usual 'no cryptic abbreviations rule'. But of course we used template.Template in the template package for its core type, not template.T. That's more illustrative of the rule. So please don't generalize from testing.T.
I am however dying to know which side of the argument url.URL falls on. Is it an example of a short name or a long one? Are you suggesting it should be url.U or that it should be url.UniformResourceLocator?
Personally I would distinguish between url.URL and context.Context by the number of characters involved & relative frequency of each. url.URL is the length of just the first context
, and my impression is that context.Context
is used far more frequently. I think if we could start over, context.C
would be a pretty nice less obtrusive name, although there's something unattractive about its higher ambiguity and inconsistency with other APIs.
Still think it's not worthwhile to introduce context.C
, but playing a bit of devils advocate to tease out the real benefit that might've come along with it.
IMO, template.Template
reads very poorly and goes counter to the "no stutter" rule. I agree that testing.B
is confusing, but if we feel that xxx.X
is an anti pattern, can we suggest an alternative? xxx.Self
, xxx.Struct
, and xxx.Ptr
all seem better than xxx.XXX
, even if it is short.
Based on the discussion above, this seems like a likely decline.
Did you read this part:
I'm also for deprecating the long, stuttering context.Context in favor of context.C.
In fact, most of the thread is in agreement. It's never a good idea to discount Go's own style guidelines --- especially in a very common new addition. But y'all will obviously do whatever you want and find some justification.
I would like to suggest at least a modification to the style guidelines if suddenly stuttering with words longer than four characters is just fine in major additions to the language.
IMO,
template.Template
reads very poorly and goes counter to the "no stutter" rule. I agree thattesting.B
is confusing, but if we feel thatxxx.X
is an anti pattern, can we suggest an alternative?xxx.Self
,xxx.Struct
, andxxx.Ptr
all seem better thanxxx.XXX
, even if it is short.
I really like this thought. The pattern of creating a package/subpackage that contains a foundational thing that would logically be named the same as the package seems popular for all the right reasons (encapsulation, scoping, tests, etc.) It just invariably creates a stutter. I've worked around this with hiding structs that implement interfaces and just keeping the interface public.
Honestly, I don't know what it would look like.
If voted down, can we at least agree on an informal convention for shortening context.Context
to something else? I would hate to run into a bunch of different ways people come up with to do that.
ctx c.Context
ctx C.Context
(conflicts with C package)ctx ctx.Context
(just stuttering in a different place)ctx context.C
(per project package alias)I think the virtue of having a single universal way of referencing context, since it’s already in use, outweighs the value of making it shorter. I think the fact that this change requires massive diffs across the ecosystem, even if the diffs were simple to prepare, is a point against it as well.
I also feel that renaming things for purely aesthetic reasons sets a bad precedent. Everybody has names they dislike, and everybody wants their braces in different places. But it's far more important to keep things consistent than to try and satisfy everyone's aesthetic preferences.
We have gofmt
, after all, to avoid aesthetic arguments like this!
"Don't stutter" is not an "aesthetic preference." It is part of the official style guideline as outlined by the original core team. Either change the style guideline or stop violating it.
@rwxrob should url.URL
be renamed to url.U
? What about hash.Hash
, draw.Drawer
, rand.Rand
, etc ...? Don't act like there's a clear precedent here.
Not all code uses context, but a significant fraction of code does. Additionally, when context is used, it tends to be viral.
For that reason, I'd argue that just as with testing.T, the usage of context should be as lightweight as possible. That can be accomplished by making it a builtin type, renaming it context.C (this proposal), or possibly something else. I like that this proposal is a small change that gets most of the brevity wins of a builtin type.
For comparison, other languages typically use thread locals to accomplish the same tasks as context. Those have zero typing cost (though they are more complex to reason about).
Lastly, I'd like to point out that migrating the name of the type has been done before. context.Context was once golang.org/x/net/context.Context.
Renaming things like this, if I recall, was one of the biggest arguments for implementing type aliases so the cost of renaming I'm not sure if a valid concern.
Even if it’s easier it’s not free. Think about how many prs this would represent, how many git blames would be broken, how many reviews would have to be issued for the PR, and what about all the repositories (I’d venture it’s most) without the infrastructure to automate this?
It’s easier, yes, but that doesn’t mean it’s free. It’s far from it.
@rwxrob should
url.URL
be renamed tourl.U
? What abouthash.Hash
,draw.Drawer
,rand.Rand
, etc ...? Don't act like there's a clear precedent here.
Every one of those was a horrible naming decision and could have been avoided. The url.URL
seems okay somehow because it was an acronym. (I'm thankful it wasn't url.Url
as other languages might have done, which is what Protobuf might have done as well.)
I simply want to point out that this issue is not going away. I agree that we need to come up with something better. I don't particularly like context.C
nor have I ever liked testing.T
but I use them because they are standards at this point. Someone has also suggested that testing.T
was essentially a huge one-off that should never have been in the language.
I agree with the biggest argument against the proposal, which is the amount of change to existing code bases that would be required. For the record, I personally never advocated for a breaking change and am still strongly against such (unless it were slated for 2.0). I'm okay with an alias while others are not.
I know this seems like much ado about nothing and that I'm just being grumpy for no reason. I apologize if that comes off as offensive. But I can report that such seemingly insignificant things (combined with the leaking of goroutines prompting the addition of Contexts into so many standard library areas in the first place) have already encouraged many developers to consider other languages (such as Rust). Specifically, they cite these type of things in defence of their own syntax issues. For them, considerations like these add to a long list of reasons to prepare ports to other languages rather than pursue the upcoming 2.0. I know I am.
I sincerely love Go and simply suggest more care be taken in such decisions in the future. So far no one likes context.Context
on this thread. Everyone is citing pre-existing conditions and "it's already there" but I think everyone agrees it was bad to begin with, at least no one yet has said, "I think context.Context
was a fine name to pick". That fact alone should hopefully give pause to those picking such names in the future. Thank you.
A bit of history: when introducing the context package, we considered three names for the type: Context, Ctx, and C. In each case, we considered not only the type name, but also the variable name people were likely to use for that type. C would have been a great type name except that the corresponding variable name, c, was commonly used for channels. The type name Ctx corresponded to the preferred variable name ctx, but context.Ctx looked odd. So we settled for the longer, stuttery type name context.Context, with preferred variable name ctx.
While this decision may look wrong to some in hindsight, please be reassured that we took care in this decision.
Most helpful comment
context.Context already has a name: Context.
testing has T but does _not_ also have Test.
Introducing an alias will only cause confusion about whether to write Context or C.
This does not seem worthwhile.