-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
Author background
- Would you consider yourself a novice, intermediate, or experienced Go programmer? experienced
- What other languages do you have experience with? python, lua, solidty, assembly
Related proposals
- Has this idea, or one like it, been proposed before? at least couldn't find it
- Does this affect error handling? no
- Is this about generics? no
Proposal
- What is the proposed change?
With pointers, arrays, array pointers and slices, allow casting and sharing references (except for arrays) for same sized integers regardless of their sign:
var v int8 = 10
a := &v
b := (*uint8)(a)
*b = 254
fmt.Println(*a, v) // -2 -2
v := make([]uint8, 1)
b := []int8(v)
b[0] = -1
fmt.Println(b) // [255]
- Who does this proposal help, and why?
It allows you to skip copies when using APIs that mix ints and uints slices and array pointers. - Please describe as precisely as possible the change to the language.
When trying to convert pointers, arrays, array pointers and slices of integers, if the integers are of the same size then the conversion works. Even if the signs do not match.
For pointers, array pointers and slices, the convertee and converted value must share whatever they reference to.
- What would change in the language spec? yes
- Please also describe the change informally, as in a class teaching Go.
First make a ~5 minute course about two's complement arithmetic, how the lower part of signed numbers of space is flipped upside down and really just a mirror of the upper halfs of unsigned numbers.
Show that additions and subtractions are sign anonym operations with two's complement.
Then reach the conclusion that (except for multiplications and divisions), in two's complement the sign doesn't really exists and is just a question of how we interpret the number.
Then with the knowlege of two's complement, explain why it just make sense. Since ints and uints are really the same thing, the only thing that change it just how you read it. It's logical golang would let you cast slices of ints to slices of uints, THEY ARE THE SAME THING!
- Is this change backward compatible? yes
The current spec says:
The value of an n-bit integer is n bits wide and represented using two's complement arithmetic.
- Orthogonality: how does this change interact or overlap with existing features? this is technically doable already with sliceheader and unsafe tricks
- Is the goal of this change a performance improvement? yes
- If so, what quantifiable improvement should we expect? avoid copies on API that mix ints and uints slices and array pointers
- How would we measure it? write a function that takes a
[]int
and pass a reference to a noescape function taking a[]uint
. Right now you need two copies, with this proposal none.
Costs
- Would this change make Go easier or harder to learn, and why? slightly harder
it's hard to make sense of this feature if you don't understand two's complement. I don't really think this is an issue, this is clearly a really optional feature, 99% of go code wont ever use this or need to. - What is the cost of this proposal? (Every language change has a cost). small
- How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected? all of them that understand the type system
- What is the compile time cost? minimal (there is a few more checks when trying to convert pointers, array, array pointers and slices)
- What is the run time cost? negative
- Can you describe a possible implementation?
func getPointyTypeThroughArrayPointers(t Type) Type {
if isPointer := t.IsPointer(); isPointer || t.IsArray() || t.Slice() {
eType := cType.Elem()
if isPointer && eType.IsArray() {
eType = eType.Elem()
}
return eType
}
return nil
}
// While trying to convert things
// convertee is the SSA Value of the argument passed in
cpType := getPointyTypeThroughArrayPointers(convertee.Type())
tpType := getPointyTypeThroughArrayPointers(targetType)
if cpType != nil && tpType != nil && cpType.IsInteger() && tpType.IsInteger() && cpType.Size() == tpType.Size() {
return b.NewValue(OpCopy, targetType, convertee)
}
- Do you have a prototype? (This is not required.) no