golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.89k stars 17.65k forks source link

proposal: Go 2: explicit exports #30572

Closed hdante closed 5 years ago

hdante commented 5 years ago

Add support for explicitly exporting symbols with an export keyword instead of implicitly exporting upper case symbols.

package package1

export (
    symbol1
    symbol2
    Symbol3
)

func symbol1() {
}

(...)

Why ?

The main motivation is allowing to export lower case symbols [edit 20190304: and non latin scripts #22188]. Secondary motivation is to have a more fine grained export control.

My opinion on current state is that golang forces usage of camel case and mixed case coding styles (not really true in theory but true in practice). I don't like using mixed case both due to personal reasons (I think it's ugly) and technical reasons (it tends to break case sensitive searches, which I think are better suited for code than case insensitive searches), and I very much prefer using coding styles analogous to Python's PEP8[1].

Suggested implementation

There are two approaches, one is compatible with go 1 and another breaks compatibility.

  1. Compatible with go 1: if there's no top-level export keyword, then symbol exporting works exactly like in go 1. If there's a top-level export keyword, then symbol exporting only exports explicit symbols.

  2. Incompatible with go 1: all exports must become explicit.

In any case, implementation would work with a new top level parsed element that would replace current (constant) export logic with a table search.

Extras

Export wildcards:

export all uppercase
export all lowercase
export a*
(etc.)

References

[1] https://www.python.org/dev/peps/pep-0008/

dotaheor commented 5 years ago

This decreases the readability. We can use the export keyword elsewhere. For example, I use the export keyword in my generics proposal to export some elements from a gen. A gen can be viewed as mini-package.

hdante commented 5 years ago

This decreases the readability.

Agreed, it slightly decreases readability. So the proposal is a compromise. A good one, I believe, that's why I proposed it.

We can use the export keyword elsewhere. For example, I use the export keyword in my generics proposal to export some elements

I'm definitely not bikeshedding over a keyword name and I'm sorry I've stolen export from your proposal. So here we go:

provide (
    symbol1
)

from a gen. A gen can be viewed as mini-package.

I'm not sure if you're suggesting this proposable is replaced by a generic mini-package (whatever that might mean), but if so I disagree. This proposal is neither about generic nor mini-packages, it's about full featured packages.

bcmills commented 5 years ago

The main motivation is allowing to export lower case symbols.

See also #22188.

hdante commented 5 years ago

The main motivation is allowing to export lower case symbols.

See also #22188.

Agreed and will edit proposal motivation.

robpike commented 5 years ago

Speaking just for myself, I have spent a long time worrying about this general topic and doing research about it. So have others. And I have concluded it's not worth fixing, if indeed it's broken at all. The clarity of the current rules, not only in their expression but also in their use in the source code of the package but also, perhaps more important, the source code of the user's code, is just too high to compromise here.

Using case to distinguish export status is one of Go's most radical but most important features. The huge positive effect on readability is profound.

ianlancetaylor commented 5 years ago

@bcmills note that for Go 2 proposals only the Go 2 proposal review group should add NeedsFix or NeedsInvestigation labels. They are how we track the state of proposals. Thanks.

hdante commented 5 years ago

Speaking just for myself, I have spent a long time worrying about this general topic and doing research about it. So have others. And I have concluded it's not worth fixing, if indeed it's broken at all. The clarity of the current rules, not only in their expression but also in their use in the source code of the package but also, perhaps more important, the source code of the user's code, is just too high to compromise here.

Disagreed. Comparing it with pretty much every other language, I think it's a very slight readability decrease and a pretty small compromise. I think the export status of a symbol within a package is mostly searched when refactoring the API, otherwise it's just directly used without additional concerns, while outside the package finding a symbol requires reading the docs or source code, both of which would have an explicit export section in this case.

but also, perhaps more important, the source code of the user's code, is just too high to compromise here.

I didn't understand here. In user's code, to use imported symbols they must be of exported type. There's no choice here. What do you mean ?

Using case to distinguish export status is one of Go's most radical but most important features. The huge positive effect on readability is profound.

Disagreed.

beoran commented 5 years ago

In Oberon, from which git borrows much of the inspiration for it's module system, identifiers that are marked with * after them are exported. The issue #22188 and this one could be solved in a backwards compatible way, by allowing a similar marker in front of or perhaps after the identifier to export it, regardless of whether or not the following identifier is upper or lower case.

Ideally, this should only be used for Unicode identifiers in scripts that don't have the upper case and lower case distinction, but that is a policy that go vet could check, not something that the compiler would have to enforce.

UFOXD commented 5 years ago

@robpike Using case to distinguish export status is one of Go's most radical but most important features. The huge positive effect on readability is profound.

I do not think so.

beoran commented 5 years ago

@robpike I agree that using case to distinguish export status is a great feature of Go.

However, seeing #22188, and also this issue, I think that we need a way to make an exception to this general rule and allow certain identifiers that do not begin with an uppercase character to be exported. An Oberon like marker seems the simplest, most backwards compatible way to do this.

ianlancetaylor commented 5 years ago

This and alternative suggestions were considered extensively in the early days of Go. We seem to have made a choice that at least for most people is working well. We aren't going to change it now.