Please do not add aliases to the language

6,144 views
Skip to first unread message

Dave Cheney

unread,
Oct 27, 2016, 10:25:25 PM10/27/16
to golang-dev
Dear all,

I'm writing to formally request that the process of adding aliases to
the language be rolled back.

Aliases were proposed via the proposal process [1], and accepted over
the strenuous objections of many external contributors, which, like
myself, have invested years of effort in advocating Go for its
simplicity and focus on readability.

It was suggested that aliases be placed behind an environment
variable, similar to the GO15VENDOREXPERIMENT, allowing Google to test
this feature internally before committing to it. This did not happen.

I was told aliases would be restricted to types as they were the only
declaration that did not have an existing analog. This did not happen.

I was told that aliases were necessary for a protobuffers feature, and
as a realist I understand that Go is sponsored by Google and that
sometimes this arrangement calls for quid pro quo. But then, this
morning I see this [2]

https://go-review.googlesource.com/#/c/32145/1/draw/go1_8.go

It is clear to me that Go programmers, including the Go team
themselves, will be unable to stop themselves from abusing this
feature to the detriment of the readability and comprehension of all
Go users.

Please, do not add aliases to the language, you're breaking my heart.

Dave

1. https://github.com/golang/go/issues/16339
2. https://go-review.googlesource.com/#/c/32145/1/draw/go1_8.go
n. https://go-review.googlesource.com/#/c/32145/1/draw/go1_8.go

Robert Griesemer

unread,
Oct 28, 2016, 12:19:20 AM10/28/16
to Dave Cheney, golang-dev
Some clarifying background information: I suggested to Dave (in-person communication) that perhaps we should introduce aliases guarded by an environment variable, not having thought enough about the consequences of such a flag when I brought it up.

The problem with an environment variable is that it effectively prevents aliases from being tried seriously, out of fear that support for the feature might disappear again. On the other hand, if they are widely (and appropriately) used, an environment variable cannot be changed anyway without breaking code. We have seen exactly this effect with GO15VENDOREXPERIMENT. Only once we enabled vendoring for good, people started using it.

Hence the decision was made by the Go team to go ahead with the minimal, regular, and quite restricted alias feature we have now implemented.

Let me say this regarding the fear of misuse: The Go language also implements the goto statement, and it is undisputed that uncontrolled use of gotos is hugely detrimental for readability and comprehension of code. Yet, there is hardly code that abuses gotos these days. But there are rare cases where a goto is exactly the right choice: when you need one (*), you really do.

I believe the same is true for alias declarations: They are seldom needed, but sometimes they are exactly the right mechanism. (**)

Thanks,
- gri

(*) Machine-generated code is a typical example.
(**) Several other important use cases besides protocol buffers were discussed in the proposal.


--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Brendan Tracey

unread,
Oct 28, 2016, 2:08:50 AM10/28/16
to Robert Griesemer, Dave Cheney, golang-dev
The problem with an environment variable is that it effectively prevents aliases from being tried seriously, out of fear that support for the feature might disappear again. On the other hand, if they are widely (and appropriately) used, an environment variable cannot be changed anyway without breaking code. We have seen exactly this effect with GO15VENDOREXPERIMENT. Only once we enabled vendoring for good, people started using it.

This change has much larger ramifications, and there is more significant objections to this proposal than the others. I haven’t been following code-reviews this cycle, but it seems that full alias support was added today, and the freeze is Nov. 1. That gives 5 days of experimentation?

Hence the decision was made by the Go team to go ahead with the minimal, regular, and quite restricted alias feature we have now implemented.

It doesn’t seem like the implementation is minimal relative to the discussion in the document. There was a suggestion that aliases would only work for variables, and there was a suggestion that one cannot make an alias to an identifier that it itself is an alias.


Let me say this regarding the fear of misuse: The Go language also implements the goto statement, and it is undisputed that uncontrolled use of gotos is hugely detrimental for readability and comprehension of code. Yet, there is hardly code that abuses gotos these days. But there are rare cases where a goto is exactly the right choice: when you need one (*), you really do.

The PR Dave linked and the example in the spec are what worry me about aliases. Go’s best feature is uniformity and legibility, and there have been design choices in Go that add a few keystrokes for the coder in order to make it easier on the reader. Aliases are so tempting for the coder to sacrifice clarity to save a few keystrokes. Right now, in Go it is so easy to find where the real code actually lies. Alias’s seem to beg for many levels of “harmless” indirection before getting to the real implementation. The PR Dave linked seems to be one such example.

When I’m reading code, if I see “Pi”, is it because the coder used “const Pi => math.Pi”, or because there is a different value defined? If I see “Exp(x)”, is it because the coder used “func Exp => math.Exp”, or because there is a custom implementation to work around #14932? I agree that this is a problem that can be encountered in Go today. Aliases, however, seem to normalize the practice, and will likely make the problem much more common. This  change also has the effect of reducing the needed keystrokes to alias a function by a factor of two or so.

Brendan Tracey

unread,
Oct 28, 2016, 2:22:31 AM10/28/16
to Robert Griesemer, Dave Cheney, golang-dev
Sorry, by “only work for variables” I meant types.

roger peppe

unread,
Oct 28, 2016, 4:23:14 AM10/28/16
to Dave Cheney, golang-dev
I have yet to see any evidence of the non-readability and incomprehension
that you suggested this feature might cause.

You can (theoretically) as easily jump to the definition of something
that's aliased as something that's not.

Perhaps you could provide some sample code that you think would be made
less readable by the draw changes you mentioned, for example?

I don't see this as a big issue, but I'm open to being convinced otherwise.

cheers,
rog.
> --
> You received this message because you are subscribed to the Google Groups "golang-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.

Markus Zimmermann

unread,
Oct 28, 2016, 5:41:11 AM10/28/16
to golang-dev
Since the code freeze is in a few days, does this mean that this language change is included in 1.8 unless some really big counterargument is found?

Brian Ketelsen

unread,
Oct 28, 2016, 7:59:36 AM10/28/16
to golang-dev
Code from the draw package for 1.8:

const Over => draw.Over
const Src => draw.Src

func Draw => draw.Draw
func DrawMask => draw.DrawMask

I find this unreadable and confusing.  One of the biggest benefits of Go for me has been its amazingly simple syntax and readability.  Adding aliases with a new operator "=>" adds a layer of indirection and confusion that is unnecessary to the language.  I find this change very disappointing, especially after the continued reassurance in the original proposal that it was only for certain critical edge cases.

image/draw doesn't appear to be either critical or an edge case.  The proliferation of alias usage will make both the standard library and other Go code harder to read and increase the mental load on developers who write and read Go.  

Please reconsider.  If alias must exist, then there should be a very clear guideline for when it can and will be used.  The bar should be set high and documented well.  Better would be removing the "feature" completely as it only adds confusion, cruft and indirection to a language I find to be the most easy to read.

Regards

Brian Ketelsen

atd...@gmail.com

unread,
Oct 28, 2016, 8:01:05 AM10/28/16
to golang-dev


On Friday, October 28, 2016 at 4:25:25 AM UTC+2, Dave Cheney wrote:
Dear all,

I'm writing to formally request that the process of adding aliases to
the language be rolled back.

The more I think about it, the more I think the proposal has merits actually. 
It could probably have been presented a little better but at least it made us think about it.

This proposal allows to build API subsets.
So out of a flat package, it becomes possible to build a tree of somewhat "virtual" packages. That should be interesting in terms of documentation presentation on godoc.

It should also enable some kind of package parametricity. (people could write their datastructures using aliases and would then just have to switch up the aliases definition as needed, still a bit manual but quite more convenient)

Paul Jolly

unread,
Oct 28, 2016, 8:14:36 AM10/28/16
to Brian Ketelsen, golang-dev
Code from the draw package for 1.8:

const Over => draw.Over
const Src => draw.Src

func Draw => draw.Draw
func DrawMask => draw.DrawMask

I find this unreadable and confusing.

Brian, Dave - has this point about readability and comprehension not been made before? Specifically in https://github.com/golang/go/issues/16339?

It is my understanding that this point has been made before, considered by the Go team, but on balance they have concluded that the benefits of aliases outweigh the costs (acknowledging the extent to which they are (un)readable is subjective).

I note however @rsc's response to @egonelbre's excellent suggestion; ideally at this point we could jump straight to the relevant part of the summary to revisit the arguments for/against and the conclusion. Or indeed if, as is possible, I have misunderstood and you are making a new point not previously covered, to have that considered and added to the summary.


Paul


robb...@gmail.com

unread,
Oct 28, 2016, 8:30:49 AM10/28/16
to golang-dev
This change feels like unnecessary syntactic sugar.

It introduces an extra layer of indirection and the new operator will be confusing to newcomers of the language getting to grips with channel syntax.

Regards

Rob Baines

Dominik Honnef

unread,
Oct 28, 2016, 8:50:25 AM10/28/16
to golang-dev
I'd like to point out that we have had weeks of arguments in
https://github.com/golang/go/issues/16339 and that all of these
arguments have been taken into consideration. Simply repeating
arguments that have already been made will not change their weight.
Unless someone has new information that would warrant reevaluating the
choice I don't see much reason for commenting here.

w...@iri-labs.com

unread,
Oct 28, 2016, 8:50:25 AM10/28/16
to golang-dev
Dear all,

I second Dave's request.

The fundamental problem is that aliases create multiple names for the same thing, which is their point.  However, 
nobody wants to see one thing referred to in multiple ways in source code, and I believe this will happen.  The second
problem is readability: the extra layer of indirection would often enough be an extra layer of noise/cognitive overhead
in reading programs.  If I want to understand an algorithm or design, I would have to de-reference aliases to accomplish this.
This seems anti-go to me.   

That said, if it ends up still accepted, please consider:

- It may be more reasonable to allow aliases for the reasons spelled out in the proposal, but to force all code in a package which
contains "alias a => b" to *disallow* using the identifier b in that package outside the context of the alias declaration, which would
help reduce the abovementioned noise but it wouldn't eliminate it.

- Overall, I think aliasing types and constants is much more reasonable than aliasing values.

Thanks,

Scott

Zellyn

unread,
Oct 28, 2016, 9:38:47 AM10/28/16
to golang-dev
The use of aliases for code organization was extensively discussed in the proposal. For example: https://github.com/golang/go/issues/16339#issuecomment-232813695

In particular, there are important cases where this makes things much better for API consumers.

Zellyn

David Norton

unread,
Oct 28, 2016, 9:45:17 AM10/28/16
to golang-dev, da...@cheney.net
Let me say this regarding the fear of misuse: The Go language also implements the goto statement, and it is undisputed that uncontrolled use of gotos is hugely detrimental for readability and comprehension of code. Yet, there is hardly code that abuses gotos these days. But there are rare cases where a goto is exactly the right choice: when you need one (*), you really do.
There's a stigma around goto that prevents its abuse. Aliasing won't have that stigma (at least not for some years). I think in practice we will see complicated aliasing graphs that make refactoring more difficult instead of less difficult. In spite of the advantages of the feature, I agree with Dave.

David
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.

Bill O'Farrell

unread,
Oct 28, 2016, 10:16:07 AM10/28/16
to golang-dev
My two cents worth: in my role as part of the IBM Hyperledger project, I have been promoting Go as the ideal language for writing "smart contracts" (a.k.a. "chaincode"). Smart contracts, like any contracts, need to be in a language which is comprehensible and clear to all agreeing parties. For this purpose the language should not be contextual -- i.e. changing from one application context to another. Go is simple and concise enough to “keep the whole language in ones head," and deliberately lacks features that can confuse programs and/or programmers. For that reason it is a much better choice then, for example, Java. If aliasing diminishes the context-free clarity of the language then I would have to agree with Dave.



On Thursday, October 27, 2016 at 10:25:25 PM UTC-4, Dave Cheney wrote:

atd...@gmail.com

unread,
Oct 28, 2016, 10:33:47 AM10/28/16
to golang-dev
It's interesting to note that the current proposal enable to refactor an API but not its code.
That's where the confusion may lie.

As such, it is probably much less dangerous than initially thought.

Rob Pike

unread,
Oct 28, 2016, 11:08:04 AM10/28/16
to atd...@gmail.com, golang-dev
Go was always intended for programming at large scale, which includes working in large software environments, with large teams, and in the presence of complicating factors such as interoperating with other languages. The alias feature is directed at solving a problem that arises in that area, which is refactoring a package in an environment too large or complex to update all the dependents of a package at once. This problem is often seen as a versioning problem, but in monorepos versioning doesn't help, while aliases do.

Now, some of Go's popularity is also because of its clarity and readability, but it is worth observing that those properties, which were also goals of the language, are sometimes in conflict with the need for programming at scale. There are other features of the language that are there for industrial-level work but clearly at odds with simplicity. Goto is the most obvious (it's present for machine-generated code). The verbosity of struct literals is another. The way interface embedding works, allowing redundancy if it's not used, is a third. There are more.

What's really different in this conversation is that, for the first time, the community is seeing the difficulty of trying to decide what to do when a new issue raises such a conflict. If we today decided to start enforcing the need to put types on the fields of struct literals, there would be an outcry, but we would do it anyway, because the benefits outweigh the cost, high though the cost is.

The alias feature is important, but it is also ugly. We know that. It is open to abuse. We know that. But we have been listening: the feature is very heavily restricted because of the many good points raised in the issue discussion. The possibility for abuse is greatly restricted, and the conversation that got us here was invaluable. But the conversation is behind us; now the time has come to try it out. If it turns out to be a real problem in practice, there are three months left to roll it back.

But I don't think it will be a problem, because I believe the community will help make sure the abuses don't happen. If you see an alias appear in code where none is necessary, complain about it, publicly. Update golint to yell whenever the feature is used.

Most important, explain to people what it is for: that, like goto, it is a necessary evil for program development in the modern world.

-rob


Russ Cox

unread,
Oct 28, 2016, 11:19:32 AM10/28/16
to Dominik Honnef, golang-dev
I want to say again what I wrote on the issue on September 15:

"""
I wish there could be widespread agreement on this issue about the merits and tradeoff here. That is our ideal for any proposal. But there is not, and after two months of discussion it seems clear that further discussion is not going to change the situation. At this point the best way to learn more is to implement this proposal and try it. We still have until the Go 1.8 release to disable it if a strong reason turns up.

Although the many important voices here are split, Rob, Robert, Ian, and I are not. Along with Ken, who is no longer working on Go on a daily basis, we were responsible for nearly all of the original design of Go, and we all agree, based on our extensive experience with Go and with very large Go code bases, that something along the lines of this proposal is needed. I ask only that you give us the benefit of the doubt on this decision and come along with us to see how it turns out.
"""

We certainly hear the people saying that they think this is making code less readable, or can or will be abused. To those people I can only ask for patience to let this process play out. 

We all have a natural bias to see "different" as "unreadable". I remember very clearly the discussion in Rob's office in January 2009 in which we - Rob, Robert, Ian, Ken, and I - decided to try "upper case means exported" for symbol visibility. I personally thought it was not a good idea and hurt readability, but the proposal addressed a real need (selective export of struct fields), and I could make no technical arguments against it other than I didn't like the way it looked. We did of course try it, and after a few weeks it stopped looking unreadable (that really meant "less like C than Go had before") and became completely natural. Today it is one of my favorite Go features, and I don't think anyone here would argue that it makes the code unreadable. To the contrary, there is actually a technical argument that it enhances readability. I realized this a few years later, when I had to do some work in an unfamiliar section of Google's C++ code base. I found it quite frustrating that I couldn't tell just from looking at a use of a method whether this was a public or private method. I'd see a call and think "wow, is that part of the public API? That would be scary." and have to go dig up the actual method definition and see that oh, it's marked private. In Go, that information is visible at each use, and I'd grown accustomed to having that information implicitly at hand when reading code. So not only was I wrong about the aesthetics of "upper case means exported" - we all adapted just fine to reading Go code written that way - but if we'd let the aesthetics make the decision, we would have cut off this other technical benefit, which we certainly discussed at the time but I think could not fully appreciate the value of until later.

Every language feature can be abused. The fact that Go uses predeclared identifiers instead of keywords when possible makes it easier to extend the language with new builtins without fear or breaking existing programs, like when we added delete. It also lets code dealing with marshalling or unmarshalling have methods with clear names like int and string (see for example go/src/encoding/gob/debug.go). These are good things. It also lets people write code like https://play.golang.org/p/3wrRikamA-, which no one would say is a good thing. We accept the fact that the last example is possible as a consequence of abuse of these more limited good things, and over time we learn conventions about what to do and not do. If you saw code like that playground example anywhere but a compiler test case (it's really go/test/rename.go), you'd encourage the author to write it differently.

Every language feature is overused at first. Experimenting is how we explore and chart the boundaries of what a language feature is and is not good for. The experiments that fail are the ones we later understand as overuse. When Go was first created, the pieces most unique to Go were channels and goroutines, so naturally we emphasized them in our talks about the language and our examples. This led to overuse of channels in particular, and in response we had to develop advice about when not to use channels: Don't use them for lightweight iterators. Don't use them when a plain mutex is sufficient, but do use them when you might use a mutex+condition variable in another language.

Back to the specifics of alias: as I said in September, based on our experience with Go and with very large Go code bases, Rob, Robert, Ian, and I believe that Go needs some kind of indirection mechanism, to enable incremental evolution of and changes to the layout of Go source trees (C/C++ programs use a combination of typedef and #define). Alias has been designed to (we think) harmonize with and be orthogonal to the rest of the language, in the spirit of Go's design, a generalization of typedef without the abuses of #define. The community feedback in the proposal discussion raised important, objective technical suggestions to limit abuse, and in response we introduced (we think) reasonable limits on alias: it can be used only at top level, it can refer only to imported symbols, it cannot refer to package unsafe. The feedback also included some important but more subjective arguments, such as the "detriment of the readability and comprehension" of Go programs. These latter arguments being subjective, all I can say is that we hear you but we disagree that they outweigh the benefits, keeping in mind especially that there is a natural bias to see different as unreadable, especially at first; that every language feature can be abused, so potential for abuse is not by itself disqualifying; and that every language feature is overused at first, as part of the natural process of exploring how it should be used.

To respond to Dave's specific points:

- Robert and others brought up the idea of an environment variable, but we decided against that. GO15VENDOREXPERIMENT was important because the changed meaning of the directory name "vendor" was going to break code that worked in Go 1.4. The environment variable let us use Go 1.5 as the "let people find out what will break and update their code" cycle. But it also created pockets of mutually uninteroperable Go code because some only compiled with GO15VENDOREXPERIMENT=1 and some only compiled without it. It was important to have that transition, but it was also an unfortunate situation. We do not want to repeat that.

- Types are not the only declaration that doesn't have an existing analog. Vars don't either, and while funcs can be worked around, the alias form is significantly cleaner. That leaves consts, for which aliases require one more character than ordinary assignment and have roughly equivalent effect. We could have excluded aliases from consts but it seemed more orthogonal to let them apply to all four instead of three of the four (or, if you argue for excluding funcs too, two of the four).

- As I hope I explained above, aliases are about incremental evolution of and changes to the layout of Go source trees. We see this in a variety of ways in large Go source trees. One common way does involve protocol buffers but is not fundamental to protocol buffers. What we see specifically is engineers doing incremental evolution of and changes to the layout of Google's source tree, in particular to protocol buffer definitions that compile to language-specific libraries. When this happens, C/C++ and Java have no problem accommodating this evolution while Go acts as a hindrance to that evolution. The ability to make this kind of change to a source tree is something C/C++ and Java programmers take for granted and are frustrated not to be able to do in Go, just as seeing the visibility of an identifier at each use is something Go programmers take for granted and are (at least sometimes) frustrated not to be able to do in C/C++ and Java. The specific protocol buffer setting was just the way that C/C++ and Java programmers helped us find this shortcoming of Go. Since Go was designed explicitly for large code bases, this is an important shortcoming to address. This is not a quid pro quo for Google. This is using our experience working in a very large source tree at Google to inform making Go work well for software development at scale. We have taken advantage of this experience throughout the design of Go, and we'll continue to do that. 

- Nigel's use of aliases to make a "draw++" package seems like a good experiment. Maybe we will find that this is a compelling way to evaluate possible evolution of existing packages and end up building tooling to support that use. Maybe we'll find that it's a mistake, like using channels as iterators, and discourage that use. These things are hard to predict. It is certainly too early to say.

This thread asking for the feature to be rolled back started less than nine hours after the compiler support was committed. That is really not enough time to make an informed decision or really even build up an informed opinion about the practical usage of a new language feature. Please be patient and in fact please join us as we experiment to find out what this feature is and is not good for.

Thanks.
Russ

Jessica Frazelle

unread,
Oct 28, 2016, 11:31:44 AM10/28/16
to Russ Cox, Dominik Honnef, golang-dev

On Oct 28, 2016 8:19 AM, "Russ Cox" <r...@golang.org> wrote:
>
> I want to say again what I wrote on the issue on September 15:
>
> """
> I wish there could be widespread agreement on this issue about the merits and tradeoff here. That is our ideal for any proposal. But there is not, and after two months of discussion it seems clear that further discussion is not going to change the situation. At this point the best way to learn more is to implement this proposal and try it. We still have until the Go 1.8 release to disable it if a strong reason turns up.
>
> Although the many important voices here are split, Rob, Robert, Ian, and I are not. Along with Ken, who is no longer working on Go on a daily basis, we were responsible for nearly all of the original design of Go, and we all agree, based on our extensive experience with Go and with very large Go code bases, that something along the lines of this proposal is needed. I ask only that you give us the benefit of the doubt on this decision and come along with us to see how it turns out.
> """
>
> We certainly hear the people saying that they think this is making code less readable, or can or will be abused. To those people I can only ask for patience to let this process play out. 
>
> We all have a natural bias to see "different" as "unreadable". I remember very clearly the discussion in Rob's office in January 2009 in which we - Rob, Robert, Ian, Ken, and I - decided to try "upper case means exported" for symbol visibility. I personally thought it was not a good idea and hurt readability, but the proposal addressed a real need (selective export of struct fields), and I could make no technical arguments against it other than I didn't like the way it looked. We did of course try it, and after a few weeks it stopped looking unreadable (that really meant "less like C than Go had before") and became completely natural. Today it is one of my favorite Go features, and I don't think anyone here would argue that it makes the code unreadable. To the contrary, there is actually a technical argument that it enhances readability. I realized this a few years later, when I had to do some work in an unfamiliar section of Google's C++ code base. I found it quite frustrating that I couldn't tell just from looking at a use of a method whether this was a public or private method. I'd see a call and think "wow, is that part of the public API? That would be scary." and have to go dig up the actual method definition and see that oh, it's marked private. In Go, that information is visible at each use, and I'd grown accustomed to having that information implicitly at hand when reading code. So not only was I wrong about the aesthetics of "upper case means exported" - we all adapted just fine to reading Go code written that way - but if we'd let the aesthetics make the decision, we would have cut off this other technical benefit, which we certainly discussed at the time but I think could not fully appreciate the value of until later.
>
> Every language feature can be abused. The fact that Go uses predeclared identifiers instead of keywords when possible makes it easier to extend the language with new builtins without fear or breaking existing programs, like when we added delete. It also lets code dealing with marshalling or unmarshalling have methods with clear names like int and string (see for example go/src/encoding/gob/debug.go). These are good things. It also lets people write code like https://play.golang.org/p/3wrRikamA-, which no one would say is a good thing. We accept the fact that the last example is possible as a consequence of abuse of these more limited good things, and over time we learn conventions about what to do and not do. If you saw code like that playground example anywhere but a compiler test case (it's really go/test/rename.go), you'd encourage the author to write it differently.
>
> Every language feature is overused at first. Experimenting is how we explore and chart the boundaries of what a language feature is and is not good for. The experiments that fail are the ones we later understand as overuse. When Go was first created, the pieces most unique to Go were channels and goroutines, so naturally we emphasized them in our talks about the language and our examples. This led to overuse of channels in particular, and in response we had to develop advice about when not to use channels: Don't use them for lightweight iterators. Don't use them when a plain mutex is sufficient, but do use them when you might use a mutex+condition variable in another language.
>
> Back to the specifics of alias: as I said in September, based on our experience with Go and with very large Go code bases, Rob, Robert, Ian, and I believe that Go needs some kind of indirection mechanism, to enable incremental evolution of and changes to the layout of Go source trees (C/C++ programs use a combination of typedef and #define). Alias has been designed to (we think) harmonize with and be orthogonal to the rest of the language, in the spirit of Go's design, a generalization of typedef without the abuses of #define. The community feedback in the proposal discussion raised important, objective technical suggestions to limit abuse, and in response we introduced (we think) reasonable limits on alias: it can be used only at top level, it can refer only to imported symbols, it cannot refer to package unsafe. The feedback also included some important but more subjective arguments, such as the "detriment of the readability and comprehension" of Go programs. These latter arguments being subjective, all I can say is that we hear you but we disagree that they outweigh the benefits, keeping in mind especially that there is a natural bias to see different as unreadable, especially at first; that every language feature can be abused, so potential for abuse is not by itself disqualifying; and that every language feature is overused at first, as part of the natural process of exploring how it should be used.
>
> To respond to Dave's specific points:
>
> - Robert and others brought up the idea of an environment variable, but we decided against that. GO15VENDOREXPERIMENT was important because the changed meaning of the directory name "vendor" was going to break code that worked in Go 1.4. The environment variable let us use Go 1.5 as the "let people find out what will break and update their code" cycle. But it also created pockets of mutually uninteroperable Go code because some only compiled with GO15VENDOREXPERIMENT=1 and some only compiled without it. It was important to have that transition, but it was also an unfortunate situation. We do not want to repeat that.
>
> - Types are not the only declaration that doesn't have an existing analog. Vars don't either, and while funcs can be worked around, the alias form is significantly cleaner. That leaves consts, for which aliases require one more character than ordinary assignment and have roughly equivalent effect. We could have excluded aliases from consts but it seemed more orthogonal to let them apply to all four instead of three of the four (or, if you argue for excluding funcs too, two of the four).
>
> - As I hope I explained above, aliases are about incremental evolution of and changes to the layout of Go source trees. We see this in a variety of ways in large Go source trees. One common way does involve protocol buffers but is not fundamental to protocol buffers. What we see specifically is engineers doing incremental evolution of and changes to the layout of Google's source tree, in particular to protocol buffer definitions that compile to language-specific libraries. When this happens, C/C++ and Java have no problem accommodating this evolution while Go acts as a hindrance to that evolution. The ability to make this kind of change to a source tree is something C/C++ and Java programmers take for granted and are frustrated not to be able to do in Go, just as seeing the visibility of an identifier at each use is something Go programmers take for granted and are (at least sometimes) frustrated not to be able to do in C/C++ and Java. The specific protocol buffer setting was just the way that C/C++ and Java programmers helped us find this shortcoming of Go. Since Go was designed explicitly for large code bases, this is an important shortcoming to address. This is not a quid pro quo for Google. This is using our experience working in a very large source tree at Google to inform making Go work well for software development at scale. We have taken advantage of this experience throughout the design of Go, and we'll continue to do that. 
>
> - Nigel's use of aliases to make a "draw++" package seems like a good experiment. Maybe we will find that this is a compelling way to evaluate possible evolution of existing packages and end up building tooling to support that use. Maybe we'll find that it's a mistake, like using channels as iterators, and discourage that use. These things are hard to predict. It is certainly too early to say.
>
> This thread asking for the feature to be rolled back started less than nine hours after the compiler support was committed. That is really not enough time to make an informed decision or really even build up an informed opinion about the practical usage of a new language feature. Please be patient and in fact please join us as we experiment to find out what this feature is and is not good for.

I think the fear stems from the fact it's already been merged. In my experience, it's harder and harder to back out things once merged. Stuff gets merged on top and as time ticks by it seems like the only way this will be reverted is if it's harming kittens or something obscene. Obviously that won't be the case as it's more just a general dislike from a lot of people so I truly think the reality is setting in.

I stand with Dave.

Bakul Shah

unread,
Oct 28, 2016, 11:35:07 AM10/28/16
to Rob Pike, atd...@gmail.com, golang-dev
Once all the files using some aliased objects are updated, may be a "refactor" tool can clean up by moving aliased objects in the right place? It would read a file indicating what aliases are to be removed. Alternatively it can warn you which files are affected. Without something like this I fear code facilitating refactoring can stick around forever. 

Asif Jalil

unread,
Oct 28, 2016, 11:56:41 AM10/28/16
to golang-dev
The goal of the alias proposal is this: 

Aliases simplify splitting packages because clients can be updated incrementally, which is crucial for large-scale refactoring.

To me, it seems clear when the aliases should be used, and also seems like the easiest and cleanest way to do refactoring in Go. I would rather have the ability to easily refactor code over potential indirection and confusion because a tool like Guru can help me with the indirection. But without the aliases, I can't easily refactor my code.

Asif

On Thursday, October 27, 2016 at 10:25:25 PM UTC-4, Dave Cheney wrote:

co...@lanou.com

unread,
Oct 28, 2016, 11:56:41 AM10/28/16
to golang-dev
A few of us on our team discussed the topic this morning.  I'm a bit dimwitted, so it took a while for me to understand the need, but they took the time to talk slow and spell it out for me.

Many of us on our team feel that while there is merit in it's use for refactoring (and we would benefit from that on our project), it comes at to high of a cost.  For one, we feel that the removal of the aliasing after a refactor likely won't happen, and the cruft will now live in the code forever.

Additionally, you are now going to live with the following insanity from package maintainers:

package L2


func
Foo() {
 println
("foo")
}

package L1


import (
 
"github.com/corylanou/tmp/l2
)

func Foo => L2.Foo


package L


import (
 
"github.com/corylanou/tmp/l1
)

func Foo => L1.Foo


Can we at least hold off on making this a part of the langauge in 1.8 until there is more discussion?  And yes, I know this has all been brought up in the issue already.

Peter Bourgon

unread,
Oct 28, 2016, 12:11:01 PM10/28/16
to Rob Pike, atd...@gmail.com, golang-dev
On Fri, Oct 28, 2016 at 5:07 PM, Rob Pike <r...@golang.org> wrote:
> Go was always intended for programming at large scale, which includes
> working in large software environments, with large teams, and in the
> presence of complicating factors such as interoperating with other
> languages. The alias feature is directed at solving a problem that arises in
> that area, which is refactoring a package in an environment too large or
> complex to update all the dependents of a package at once. This problem is
> often seen as a versioning problem, but in monorepos versioning doesn't
> help, while aliases do.
>
> Now, some of Go's popularity is also because of its clarity and readability,
> but it is worth observing that those properties, which were also goals of
> the language, are sometimes in conflict with the need for programming at
> scale. There are other features of the language that are there for
> industrial-level work but clearly at odds with simplicity. Goto is the most
> obvious (it's present for machine-generated code). The verbosity of struct
> literals is another. The way interface embedding works, allowing redundancy
> if it's not used, is a third. There are more.
>
> What's really different in this conversation is that, for the first time,
> the community is seeing the difficulty of trying to decide what to do when a
> new issue raises such a conflict. If we today decided to start enforcing the
> need to put types on the fields of struct literals, there would be an
> outcry, but we would do it anyway, because the benefits outweigh the cost,
> high though the cost is.
>
> The alias feature is important,

The case for this statement has unfortunately not been made convincingly.

I stand with Dave. Please don't move forward with this feature.


> but it is also ugly. We know that. It is
> open to abuse. We know that. But we have been listening: the feature is very
> heavily restricted because of the many good points raised in the issue
> discussion. The possibility for abuse is greatly restricted, and the
> conversation that got us here was invaluable. But the conversation is behind
> us; now the time has come to try it out. If it turns out to be a real
> problem in practice, there are three months left to roll it back.
>
> But I don't think it will be a problem, because I believe the community will
> help make sure the abuses don't happen. If you see an alias appear in code
> where none is necessary, complain about it, publicly. Update golint to yell
> whenever the feature is used.
>
> Most important, explain to people what it is for: that, like goto, it is a
> necessary evil for program development in the modern world.
>
> -rob
>
>

john...@gmail.com

unread,
Oct 28, 2016, 12:42:11 PM10/28/16
to golang-dev
Wow, I get up Friday morning and discover that there's this huge thread  about a feature I had no idea was being considered. At one time, this wouldn't have happened: features like this would have had at least a preliminary design document posted someplace I could find them. However, posting to the wiki seems to have been discontinued several releases ago, and I have no idea where, or even whether, it's possible to find them.

It would be helpful for people like me who are not involved with the day-to-day work of the Go development process to have a way of finding this kind of change proposal so we'd have time to think it through, or at least adjust to it.

This is a bit frustrating, because I keep my eye on what's being proposed for Python. Nothing gets into that language without a formal proposal (called a PEP for Python Enhancement Proposal), which is numbered and posted in a standard location. The practice mentioned above served the same purpose.

That said, if I understand the discussion to this point, the primary use case is to allow a quick, minimally expensive in developer time, fixup when a project's import tree changes under it. I presume there are reasons why standard refactoring tools aren't appropriate in this case.




Brad Fitzpatrick

unread,
Oct 28, 2016, 12:44:23 PM10/28/16
to john...@gmail.com, golang-dev

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.

murali

unread,
Oct 28, 2016, 1:03:03 PM10/28/16
to golang-dev
I find this quite convincing to me than the one regarding large-scale refactoring (they appear to be the two sides of the same coin though).

By the way, I wonder if aliases would make #11647 more feasible.

Egon Elbre

unread,
Oct 28, 2016, 1:16:08 PM10/28/16
to golang-dev, atd...@gmail.com


On Friday, 28 October 2016 08:08:04 UTC-7, Rob Pike wrote:
Go was always intended for programming at large scale, which includes working in large software environments, with large teams, and in the presence of complicating factors such as interoperating with other languages. The alias feature is directed at solving a problem that arises in that area, which is refactoring a package in an environment too large or complex to update all the dependents of a package at once. This problem is often seen as a versioning problem, but in monorepos versioning doesn't help, while aliases do.

Now, some of Go's popularity is also because of its clarity and readability, but it is worth observing that those properties, which were also goals of the language, are sometimes in conflict with the need for programming at scale. There are other features of the language that are there for industrial-level work but clearly at odds with simplicity. Goto is the most obvious (it's present for machine-generated code). The verbosity of struct literals is another. The way interface embedding works, allowing redundancy if it's not used, is a third. There are more.

What's really different in this conversation is that, for the first time, the community is seeing the difficulty of trying to decide what to do when a new issue raises such a conflict. If we today decided to start enforcing the need to put types on the fields of struct literals, there would be an outcry, but we would do it anyway, because the benefits outweigh the cost, high though the cost is.

The alias feature is important, but it is also ugly. [snip]

I think this is the wrong wording, the correct would be 

"Refactoring in a big code-base is important -- and alias feature is the best solution we came up with".

The problem I see with alias is that I cannot see how it helps refactoring nor are there proper real-world examples in the design document how it helps refactoring. So, what is the exact refactoring workflow?

Most of the useful "refactorings" I do are type splitting and merging; adding/removing/replacing fields and name changes... it helps with moving things between packages -- but type-splitting/merging are more useful.

The splitting of packages is an interesting use-case ... but yet again I failed to find a proper case-study. The best I saw was few comments how it would help some package -- but I didn't understand how.

Because I cannot really see how it would work and/or the good use-cases... I stand with Dave.

What I would like to see:
1. this is the starting situtation: (e.g. we have 4 teams of programmers, each having 5 programmers; all are using git except X,Y,Z; and we use codereview plugin)
2. this is the starting state of the code base: (e.g. here we have a struct field that needs to be renamed/removed)
3. here is Team1:Person2 making a CL to remove the struct field
4. here is other teams making conflicting CL-s
5. ....
N. all is finally in a consistent state with the struct field removed. With a few pending CL-s for Q and R.

Hopefully having this alias feature will make it easier to produce such use-cases...

(And please no facilitated examples, facilitated examples for work poorly because it's impossible to tell whether the thing you are trying to do is a good idea in the first place. Also, make it a Google Doc -- threads are not suitable for it.)

// PS: I feel like this whole thread will deteriorate again without a proper document to write up things. Go Packaging Proposal Process (https://docs.google.com/document/d/18tNd8r5DV0yluCR7tPvkMTsWD_lYcRO7NhpNSDymRr8/edit) is a good example how to do it.

+ Egon

Robert Griesemer

unread,
Oct 28, 2016, 1:27:53 PM10/28/16
to golang-dev
Hello everybody;

Almost every single comment in this e-mail thread has been discussed in detail in the proposal, which has been out for more than 3 months now.

If you're new to this discussion, or if you have any new insight, comment, or other relevant opinion, please see and comment at


--

roger peppe

unread,
Oct 28, 2016, 1:32:05 PM10/28/16
to golang-dev
I honestly don't think this will hurt readability much,
and I care deeply about readability.

I have however just realised what feels odd to me about the
specific syntax:

type A => B

makes it look like A flows to B, but actually the flow is the
other way.

type A <= B

looks odd though.

I kinda wish it had been decided to go with type aliases only.

type A = B

because mutable global variables are almost always a smell, and
functions and constants are trivial to do already.

Rob Pike

unread,
Oct 28, 2016, 1:40:27 PM10/28/16
to roger peppe, golang-dev
This too was talked about. One person's flow (information flows from B to A) is another's reference (A refers to B). Either makes sense, but the right-pointing arrow seemed consistent with other things in our universe, such as how symlinks are presented by ls -l on Unix. And since an alias is analogous to a symlink, that seemed the right choice.

-rob


Chris Hines

unread,
Oct 28, 2016, 1:45:27 PM10/28/16
to golang-dev, atd...@gmail.com
Although my mind remains open, Egon has perfectly expressed my current thoughts on the aliasing feature. I read the original proposal and followed the discussion for several weeks after. Since then I have not followed the work as closely. I've seen several creative uses for aliases tossed out, but I have yet to fully understand the intended workflow for their originally declared purpose. I have not passed judgement on aliases yet, but like Egon, I would like to see a detailed walkthrough of an alias enabled refactoring on a real code base documented during this trial period. I think it would help everyone involved to see something concrete.

Chris 

Jaana Burcu Dogan

unread,
Oct 28, 2016, 2:09:49 PM10/28/16
to roger peppe, golang-dev
On Fri, Oct 28, 2016 at 10:31 AM, roger peppe <rogp...@gmail.com> wrote:
I honestly don't think this will hurt readability much,
and I care deeply about readability.


I agree with this. There are already many opportunities to create indirection in Go, but we have been historically good at calling them out.

type I interface{}

I cannot remember how many times I have seen people giving feedback against this particular type def or creating unnecessary shortcuts such as,

var TODO = context.TODO()

As long as we communicate aliases well, I don't believe they will automatically become a disaster for readability.
 
I have however just realised what feels odd to me about the
specific syntax:

   type A => B

makes it look like A flows to B, but actually the flow is the
other way.

   type A <= B

looks odd though.

I kinda wish it had been decided to go with type aliases only.

   type A = B

because mutable global variables are almost always a smell, and
functions and constants are trivial to do already.

Vitor De Mario

unread,
Oct 28, 2016, 2:12:20 PM10/28/16