Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: spec: forbid zero-size arrays #21765

Closed
Ravenslofty opened this issue Sep 5, 2017 · 8 comments
Closed

proposal: spec: forbid zero-size arrays #21765

Ravenslofty opened this issue Sep 5, 2017 · 8 comments
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Milestone

Comments

@Ravenslofty
Copy link

At the moment, the Go specification on array types states "the length ... must evaluate to a non-negative constant representable by a value of type int". This means the language (and the Go Playground) allows the definition of a [0]int type which has no practical value.

With this in mind, I propose to reword the above line of specification from "a non-negative constant" to "a positive, non-zero constant", and make it an error to define a zero-size array. While this is technically a breaking language change, a quick grep of the Go corpus turns up zero definitions of a zero-sized array, and I don't see how it could be practically used in the wild.

@gopherbot gopherbot added this to the Proposal milestone Sep 5, 2017
@dominikh
Copy link
Member

dominikh commented Sep 5, 2017

Grepping the Go corpus yields 2318 instances of [0]byte. Furthermore, forbidding arrays of length zero would be a special case: strings, slices, maps and channels all can have a length of zero. Structs can have zero fields, interfaces can have zero methods.

What would be the benefit of adding this restriction?

@Ravenslofty
Copy link
Author

Ravenslofty commented Sep 5, 2017

My hard disk is a lot slower than yours, but a few examples:

Quickly scanning bazil.org/fuse/fuse_kernel.go:

type dirent struct {
	Ino     uint64
	Off     uint64
	Namelen uint32
	Type    uint32
	Name    [0]byte
}

[0]byte appears to be the equivalent of void here, and arguably shouldn't be used. I don't understand the comment enough to say.

github.com/BurntSushi/toml/encode_test.go uses zero-sized arrays to test for crashing on the situation of having a zero-sized array. That would be a test that would be unneccessary if zero-sized arrays were illegal anyway.

My proposal is that zero-sized arrays have no practical use. Unlike slices, strings (assuming I understand how strings work) or maps, arrays cannot be dynamically resized at runtime, meaning that a zero-length array is immutably zero length.

I do not understand channels as well as I should, but my interpretation of the spec is that a zero-length channel has practical use as synchronised communication.

@martisch
Copy link
Contributor

martisch commented Sep 5, 2017

There are uses for them in the std library:

src/regexp/exec.go

// arrayNoInts is returned by doExecute match if nil dstCap is passed
// to it with ncap=0.
var arrayNoInts [0]int

To me it looks like it would break backwards compatibility and break existing valid code. Would also require implementing additional constraint checking in the compiler.
What would be the benefit of adding this restriction?

@randall77
Copy link
Contributor

[0]int is as useful as struct{}. Which is to say, actually pretty useful. For instance, a set with elements of type K can be implemented as a map[K][0]int.
Zero-sized types can also be used as location placeholders for various unsafe trickery.
We could probably require that people use struct{} instead of a zero-sized array for a zero-sized type. But I don't see a compelling enough reason to change the language for this.

Disallowing [0]int but allowing make([]int, 0) also seems counter-intuitive.

@mvdan mvdan added v2 An incompatible library change LanguageChange Suggested changes to the Go language labels Sep 5, 2017
@mdempsky
Copy link
Contributor

mdempsky commented Sep 5, 2017

It's not clear to me what the proposed benefit of removing [0]T from the language would be.

For example, zero-width types complicate the language (e.g., needing to declare that pointers can alias) and compiler and runtime (e.g., needing to worry about pointers to trailing zero-width fields), and I think it could be worth removing [0]T if it enabled dropping zero-width types. However, we would also have to remove struct{}, which I don't think is going to happen.

Otherwise, I don't see the point in breaking the handful of applications today that have found uses for [0]T.

@bcmills
Copy link
Contributor

bcmills commented Sep 6, 2017

[0]T is strictly more useful than struct{}, because it can be used to force alignment in structs that will be passed to C, assembly, or kernel APIs (see #18950 (comment)).

Until and unless we have some other means to declare alignment (#19057), there is no other way to align struct fields without adding unnecessary padding.

@davecheney
Copy link
Contributor

@ZirconiumX Thank you for the proposal. As it stands, it's hard to make out the context that lead you to propose this change to Go. Would you be able to give some more background, for example:

What is the problem that you are facing that motivated you to make this proposal? As it stands this looks like addressing something that you see as unnecessary. Be aware that others may consider the existence of [0]int orthogonal.

How would this affect other programmers who have used zero sized arrays in their code? What alternatives can they use if this proposal were implemented?

Given the backward compatibility requirements of Go 1, proposals to remove something from the language spec must address a very serious problem to justify the disruption. As it stands, it is unlikely that this proposal would be adopted for Go 1, and without sufficient justification would not be accepted for future Go releases because, while inconsistent to you, has already been dealt with by the compiler for many years.

Thank you in advance for your considered response.

@Ravenslofty
Copy link
Author

Github ate my previous response, so I'll try again.

@ZirconiumX Thank you for the proposal. As it stands, it's hard to make out the context that lead you to propose this change to Go. Would you be able to give some more background, for example:

I was collecting a group of corner cases in the Go specification, and noted that the array size spec allowed a zero-length array. I asked my friends and #golang-nuts if anybody could find a use for an array that could not legally hold data according to the same language specification. Thus I filed a specification bug because this did not make sense.

What is the problem that you are facing that motivated you to make this proposal?

I have no specific problem with zero-sized arrays; they are just very confusing and will catch somebody out.

As it stands this looks like addressing something that you see as unnecessary. Be aware that others may consider the existence of [0]int orthogonal.

Of course, but arrays are different to the other types like map/chan etc in that they do not expand dynamically (there are slices for that). So unlike a zero-size slice or a zero-size string, there is little practical use for a zero-size array.

How would this affect other programmers who have used zero sized arrays in their code?

I would consider the use of zero-sized arrays to be laiden with traps. For example, while I do not claim to be an experienced Go programmer, I was caught off-guard by @bcmills mentioning [0]T being an apparent idiom for forcing alignment in a struct, and nowhere is it mentioned in Effective Go. How many other people would likewise be thrown off-guard by it? I believe a proper form of alignment specification is the answer here, and that's separate to this proposal.

What alternatives can they use if this proposal were implemented?

I covered my opinion on alignment above.

Using map[K][0]int to represent a set seems very hackish to me; surely there are better data structures for that?

Given the backward compatibility requirements of Go 1, proposals to remove something from the language spec must address a very serious problem to justify the disruption. As it stands, it is unlikely that this proposal would be adopted for Go 1, and without sufficient justification would not be accepted for future Go releases because, while inconsistent to you, has already been dealt with by the compiler for many years.

Mmm, okay, fine.

Thank you in advance for your considered response.

This probably sounded more like a temper tantrum than a considered response.

@golang golang locked and limited conversation to collaborators Sep 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

9 participants