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: reflect: add constants for size of int, bool, etc. #29982

Open
robpike opened this issue Jan 29, 2019 · 15 comments

Comments

@robpike
Copy link
Contributor

commented Jan 29, 2019

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:

package reflect

const (
  SizeofInt = <size on this machine>
  SizeofUint = SizeofInt
  SizeofBool = 1
  SizeofFloat64 = 8
  //...
)

These would be defined for primitive types only, not slices, maps, etc. You'd still need the unsafe package to handle them.

@gopherbot gopherbot added this to the Proposal milestone Jan 29, 2019

@gopherbot gopherbot added the Proposal label Jan 29, 2019

@mvdan

This comment has been minimized.

Copy link
Member

commented Jan 30, 2019

The closest thing we have right now is bits.UintSize, which would be equivalent to the proposed reflect.SizeofUint: https://golang.org/pkg/math/bits/#pkg-constants

Have you considered reversing the names, like IntSize and UintSize? They'd be a bit shorter and easier to remember, I think.

I also wonder if we could remove bits.UintSize in the future, if all these constants are available in the reflect package.

@rogpeppe

This comment has been minimized.

Copy link
Contributor

commented Jan 30, 2019

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 math/bits:

// UintPtrSize is the size of a uintptr in bits.
const UintPtrSize = uintPtrSize

everything else is OK without constants AFAICS.

@rogpeppe

This comment has been minimized.

Copy link
Contributor

commented Jan 30, 2019

we solve 90% of the problem by add easy-to-use constants to a safe package

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?

@rsc

This comment has been minimized.

Copy link
Contributor

commented Jan 30, 2019

@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.

@andybons

This comment has been minimized.

Copy link
Member

commented Mar 27, 2019

@robpike have your thoughts on this issue changed at all?

@robpike

This comment has been minimized.

Copy link
Contributor Author

commented Mar 27, 2019

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.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Apr 24, 2019

we solve 90% of the problem by add easy-to-use constants to a safe package, such as:

package reflect

const (
  SizeofInt = <size on this machine>
  SizeofUint = SizeofInt
  SizeofBool = 1
  SizeofFloat64 = 8
  //...
)

These would be defined for primitive types only, not slices, maps, etc.

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:

const (
    IntSize = ...
    PtrSize = ...
)

Maybe IntSize belongs in math?
Math is mostly about floats, but it does have MaxInt8 etc.

Maybe PtrSize belongs in runtime?
It would be unfortunate for code to import reflect just to find out how big an int is (not as unfortunate as importing unsafe but still unfortunate).

@andybons

This comment has been minimized.

Copy link
Member

commented May 14, 2019

@robpike what do you think?

@robpike

This comment has been minimized.

Copy link
Contributor Author

commented May 14, 2019

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.

@robpike

This comment has been minimized.

Copy link
Contributor Author

commented May 14, 2019

They could even go into builtin...

@smasher164

This comment has been minimized.

Copy link
Member

commented Aug 1, 2019

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.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Aug 6, 2019

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.
We could put them elsewhere but no other package seems better.
We don't want to import reflect just for sizes.
Using runtime (next to runtime.GOARCH) would be defensible but maybe not better than math/bits.
Math would be a bit odd since there is nothing about unsized integers in its API today.
And 'builtin' is not a real package at the moment.
Maybe math/bits is the best place.

bits.UintSize already exists.
Do we need to add bits.IntSize too?

bits has nothing to do with pointers, so bits.PtrSize would be a mistake.
Probably reflect.PtrSize is the answer there? Reflect is all about pointers.

So it looks like the open question are:

  1. Do we add bits.IntSize = UintSize ?
  2. Do we add reflect.PtrSize = ... ?
@robpike

This comment has been minimized.

Copy link
Contributor Author

commented Aug 6, 2019

If you put UintSize into bits, I'd put PtrSize there too so they're in one place.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Aug 20, 2019

@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.

@robpike

This comment has been minimized.

Copy link
Contributor Author

commented Aug 21, 2019

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.