-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
sizeof: new package with constants for Int, Uint, Uintptr, Int8, Float64, etc #29982
Comments
The closest thing we have right now is Have you considered reversing the names, like I also wonder if we could remove |
I think I'm generally -1 on this proposal. I can't see the sizes of any numeric types other than int, uint and uintptr changing in the future. For example, is it remotely possible that uint64 ever gets represented with something other than 8 bytes? I suspect not. Instead I'd suggest adding one constant to
everything else is OK without constants AFAICS. |
I'd be interested to hear more about what the problem actually is. What's the use case for knowing representation sizes (as opposed to numeric bit sizes) unless it's to go along with other unsafe operations? |
@rogpeppe it would be weird to add UintptrSize and not have any routines involving uintptrs in math/bits. (Also it's Uintptr because the lowercase is not uintPtr.) Adding new constants to reflect does not seem nearly as nice or general as the current unsafe.Sizeof. If we can't find a better home for that language-level constant mechanism, probably its best to just leave it where it is and not have two. |
@robpike have your thoughts on this issue changed at all? |
I still think it's wrong that the library says that to find the size of int is unsafe: calling unsafe.Sizeof(int) just isn't unsafe. You can compute its size, but it's really tricky and hard to work out from first principles (see the constants blog post for the mechanism). I still think a handful of constants in someplace safe is a friendlier solution than using unsafe.Sizeof for this subset of its use. |
Nearly all the primitive types are already sized (uint8, float64 etc). The only unsized types are int, uint, uintptr, and bool, right? I am skeptical that there is so much code doing unsafe.Sizeof(true) to find out how big a bool is. Checking the size of an int is certainly common. bits.UintSize is the size of an int or uint in bits (but its bits). Maybe we could add to reflect just:
Maybe IntSize belongs in math? Maybe PtrSize belongs in runtime? |
@robpike what do you think? |
Sounds fine. I'd be fine with them all in reflect - it's a reflective operation to ask a question about a type, and reflect is part of everything that formats values so it's not a burden to the binary - but am open to other options. Maybe even a standalone tiny package of constants. |
They could even go into builtin... |
I'm not sure if the ship has sailed on the package to which these belong, but doesn't it seem inconsistent to already have the bit size for a builtin in math/bits (uint), and still declare the bit sizes for int and uintptr in separate packages? I see math/bits as the singular location containing operations and constants to deal with integral types at the bit-level. Declaring these in separate packages would only serve to confuse users and add to the number of dependencies. |
Summary of discussion so far: I think from the original proposal we're down to IntSize, UintSize, and PtrSize. For location, math/bits doesn't seem perfect but bits.UintSize already exists. bits.UintSize already exists. bits has nothing to do with pointers, so bits.PtrSize would be a mistake. So it looks like the open question are:
|
If you put UintSize into bits, I'd put PtrSize there too so they're in one place. |
@robpike, sorry for the delayed response. I am worried about the message putting PtrSize into math/bits sends. Math/bits is entirely arithmetic operations on integers, hardly any of which are appropriate or even safe to do on Go pointers (maybe TrailingZeros). It would stick out in the API docs ("what is this doing here?"). In contrast, reflect has lots of pointer stuff. |
@rsc, I think a comment can cover that well enough, and it sends a nice message to put all the Size constants in one place. |
Just to clarify, is the current consensus to change the constant declarations in math/bits to something like the following?
|
@smasher164, I think the consensus is to add I still have serious reservations about adding PtrSize anywhere but reflect. Looking through the conversation history I am not sure why we started talking about the number of bits in a pointer at all. @rogpeppe, you suggested adding UintptrSize to math/bits. Ian points out that UintptrSize == UintSize now on all supported architectures but of course we might not want to assume that for all time. But still, why care about UintptrSize at all? |
Ping @rogpeppe or anyone else for why we need UintptrSize at all. |
@rsc For consistency. Why should one numeric type with implementation-defined size be different from the others? |
I will reiterate a point I made above: Much of the argument here is a consequence of the decision to put this in math/bits, where I don't think it belongs. Why not create a new package, called say size, and put them there? This also opens a place to put helpful functions to safely compute things like the size of an array or struct or slice or possibly? map. |
I have used the size of Later, after much more reading, I got the feeling that garbage collection could move objects while I was using such a set, so I made the keys be just a new field on T; the only requirement for them to remain The overall experience suggests to me that anyone who wants to use the size of |
Talked to @robpike about this. Given the trouble with finding an existing home for these, he suggests a new package:
These could almost be defined as, for example, Having a separate package eliminates all the problems with none of the existing packages being right. Retitling for this new idea. |
Considering the // Package sizeof defines the sizes of basic Go types in bytes.
package sizeof
const (
Bool = 1
Byte = Uint8
Channel = Uintptr
Complex128 = 16
Complex64 = 8
Float32 = 4
Float64 = 8
Function = Uintptr
Int = Uint
Int16 = 2
Int32 = 4
Int64 = 8
Int8 = 1
Interface = Uintptr << 1
Map = Uintptr
Rune = Int32
Slice = Uintptr + Int<<1
String = Uintptr + Int
Uint = word
Uint16 = 2
Uint32 = 4
Uint64 = 8
Uint8 = 1
Uintptr = Uint
word = 4 << (^uint(0) >> 32 & 1) // 4 or 8
) We would also want to fixup package bits
import "sizeof"
// UintSize is the width of a uint in the current runtime.
const UintSize = sizeof.Uint << 3 package strconv
import "math/bits"
// IntSize is the size in bits of an int or uint value.
//
// Deprecated: please use math/bits.UintSize.
const IntSize = bits.UintSize |
Interface, Slice and String have different sizes on 32 bit architectures. |
Good catch, I have redefined them based on their implementations in
|
Change https://golang.org/cl/241679 mentions this issue: |
Change https://golang.org/cl/242018 mentions this issue: |
Was it considered to add a new builtin function |
Change https://golang.org/cl/242783 mentions this issue: |
CL 242783 is a proof-of-concept for adding a new |
Notably, I proposed extending unsafe.Alignof and unsafe.Sizeof to accept type arguments back in 2015: #12994 It was rejected because "I think this simplifies very few real programs." Where's the data that The regular expression I posted in #12994 now lists 166 instances of By comparison, CL 242018 finds just 6 instances in the standard library that benefit from this (which could have been refactored using an "internal/sizeof" package already). The same internal Google codebase has just 12 instances of Edit: The internal Google code base also has 3 instances of |
@mdempsky, commenting on an accepted issue to suggest new ideas isn't something we typically see. |
FWIW, I worry about sizeof(x) overfitting to expectations from C. I spoke to Rob about this, since he suggested the package approach in the first place, and he pointed out that having a package means we can extend it in interesting ways in the future, including things like calculating the actual memory size of a linked data structure, or a map, or a slice, or some other thing entirely, none of which is possible if we instead put C's sizeof(x) into the Go spec. |
Given the other suggestions that have come in related to this package, it seems like we should move it back into active discussion. In the previous comment I mentioned that having a package means we can have more interesting functionality like sizeof.Map - how much memory does the entire map take up? - and so on. So maybe we should put off introducing these basic constants until we have a full picture of what we want the package to be. I've put it on hold, though, since we don't have bandwidth to elaborate the other features right now. |
By adding |
@go101, I don't think that proposal is really viable for the type literally named I think if that proposal were adopted, it would have to introduce a new type with a name other than |
How about introduce a new generic builtin function func sizeOf[T any]() uintptr |
Related to #50019 I guess. The main reason a function is not sufficient is that the result of a function call isn't a constant, so couldn't be used to parameterize array lengths etc. |
Not sure if it can be used as an opportunity to introduce |
See the tail of the (closed) proposal #5602. There I suggested that instead of making unsafe.Sizeof a safe thing, which it still kinda isn't in general, we solve 90% of the problem by add easy-to-use constants to a safe package, such as:
These would be defined for primitive types only, not slices, maps, etc. You'd still need the unsafe package to handle them.
The text was updated successfully, but these errors were encountered: