What happens when I range over an uninitialized pointer to array in golang - go

I have this code
var j *[33]byte
for i := range j {
fmt.Println(j[i])
}
Now when I run this code I get nil pointer dereference error when I try access values in j. I'm not sure why I was even able to enter the loop in the first place considering my pointer is uninitialized.
I know an uninitialized array has all its values set to their zero value. That is
var a [5]int
Will have a default value of [0, 0, 0, 0, 0].
But I don't understand what golang does when you don't initialize a pointer to an array. Why is range able to range over it even though its nil?

From the Go spec Range Clause:
... For an array, pointer to array, or slice value a, the index
iteration values are produced in increasing order...
so as a convenience the Go language is dereferencing the pointer with the intent to iterating over its elements. The fact that the pointer is nil is a simple programming error. If this can occur, one should have a runtime check in place to guard against it.
Static analysis may be able to detect this type of bug ahead of time - but what if the variable j is accessible from another goroutine - how would the compiler know for sure that another goroutine may update it to a non-nil value right before the range loop is reached?

Go has a zero value defined for each type when you initialize a variable with var keyword (this may change when using :=, ideally used when need copies of values or specific values). In the case of the pointer the zero value is nil (also maps, interfaces, channels, slices, and functions) in case of array of type int the zero value is 0.
So, to answer your question, Go is able to iterate because you have 33 valid spaces idependently of what value is inside of that position. You can check the diference between slices and arrays on the Golang documentation to have more insights on why is that.

Related

How to Define a Constant Value of a User-defined Type in Go?

I am implementing a bit-vector in Go:
// A bit vector uses a slice of unsigned integer values or “words,”
// each bit of which represents an element of the set.
// The set contains i if the ith bit is set.
// The following program demonstrates a simple bit vector type with these methods.
type IntSet struct {
words []uint64 //uint64 is important because we need control over number and value of bits
}
I have defined several methods (e.g. membership test, adding or removing elements, set operations like union, intersection etc.) on it which all have a pointer receiver. Here is one such method:
// Has returns true if the given integer is in the set, false otherwise
func (this *IntSet) Has(m int) bool {
// details omitted for brevity
}
Now, I need to return an empty set that is a true constant, so that I can use the same constant every time I need to refer to an IntSet that contains no elements. One way is to return something like &IntSet{}, but I see two disadvantages:
Every time an empty set is to be returned, a new value needs to be allocated.
The returned value is not really constant since it can be modified by the callers.
How do you define a null set that does not have these limitations?
If you read https://golang.org/ref/spec#Constants you see that constants are limited to basic types. A struct or a slice or array will not work as a constant.
I think that the best you can do is to make a function that returns a copy of an internal empty set. If callers modify it, that isn't something you can fix.
Actually modifying it would be difficult for them since the words inside the IntSet are lowercase and therefore private. If you added a value next to words like mut bool you could add a if mut check to every method that changes the IntSet. If it isn't mutable, return an error or panic.
With that, you could keep users from modifying constant, non-mutable IntSet values.

Append a slice from a map value does not affect the map

mp := map[int][]int{}
slice := make([]int, 0, 1)
fmt.Printf("slice address:%p\n", slice)
mp[0] = slice
slice = append(slice, 1)
fmt.Println("after append")
fmt.Printf("slice address:%p\n", slice)
fmt.Println("slice:", slice)
fmt.Println("mp[0]:", mp[0])
fmt.Printf("mp[0] address:%p\n", mp[0])
output:
slice address:0xc042008f78
after append
slice address:0xc042008f78
slice: [1]
mp[0]: []
mp[0] address:0xc042008f78
The address of the slice does not change as its cap is large enough during append. So why the map value does not take effect?
As explained in Go Slices: usage and internals, two slices may point to the same memory location, but may have different len and cap attributes.
In Golang it is mentioned in blog on Go Slices: usage and internals
Slicing does not copy the slice's data. It creates a new slice value
that points to the original array. This makes slice operations as
efficient as manipulating array indices. Therefore, modifying the
elements (not the slice itself) of a re-slice modifies the elements of
the original slice:
slice = append(slice, 1)
So in the above case it is creating a new slice with pointing to the same original underlying array. That is the reason it is showing the same address.
To get the data of underlying array pointed by slice use reflect with unsafe:
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
data := *(*[1]int)(unsafe.Pointer(hdr.Data))
Working code on Playground
This is caused by the fact, that multiple slices can be backed by the same data but use different "sections" of the data. This means, that yes, an element is added to the data backing mp[0], but the length of the slice in mp is not changed. You can do that manually:
fmt.Println(mp[0][:1])
which does print [1].
You can grow any slice to it's capacity without changing the underlying data by using slice[:cap(slice)]. slice[:n] will panic if cap(slice) < n.
slice[n] on the other hand will panic when len(slice) <= n. I assume that the former is possible to allow the growing of slices without changing the underlying data (as far as that is possible). The latter, I would say, is "normal" behavior.
This also explains why mp[0][:2] panics, as cap(mp[0]) is 1.
For more details you might want to read this official blog post, as suggested by Flimzy.

About Golang pointer,Why is that?

What happened ?
var n interface{} = 2
var pn = &n
var pf = (*int64)(unsafe.Pointer(pn))
fmt.Println(pf)
fmt.Println(pn)
fmt.Println(*pn) // 2
fmt.Println(*pf) // not 2
*pf = 9
fmt.Println(*pn) //error invalid memory address or nil pointer dereference
fmt.Println(*pf) // 9
My question is Why is *pf not equal to *pn and error ?
Thanks for your reply.
n is of an interface{} type, so in memory it is represented by a struct of 2 values: a type and data. The type comes first. So you dereference it and interpret as a number.
*pf = 9 breaks that structure, so next time you try to dereference it - the runtime fails.
For simplicity let’s think we have 64-bit machine.
n is pair of 2 words of 64-bit: first is a pointer to a variable, second is a pointer to information about type - so called itab.
When you get a value pointed by pn compiler knows you want value of an interface, so it goes by the first pointer and returns int value. Compiler thinks pf is a pointer to float64 . So it lets. You to overwrite first word in the interface n with some likely incorrect address (equal to binary value of 9.0). Next time you see the value in the interface compiler uses incorrect address. And return some garbage or even SegFault.
That’s why it’s called unsafe.Pointer and is not recommended to use. Until you have very serious concerns.
An interface value contains information about the type of the data it contains and then the actual value (or a pointer to the value). When you cast a pointer to the interface to *int64, the *int64 will point into some random data in the interface value (which today happens to be a pointer to the information about the type, but this is allowed to change, this part of the language is not covered by the compatibility guarantee). When you then overwrite that data, things break, unsafe is called unsafe for a reason.
*pf is not equal to *pn because they have different types even though they might contain the same bit pattern.

Go error: non-constant array bound

I'm trying to calculate the necessary length for an array in a merge sort implementation I'm writing in go. It looks like this:
func merge(array []int, start, middle, end int) {
leftLength := middle - start + 1
rightLength := end - middle
var left [leftLength]int
var right [rightLength]int
//...
}
I then get this complaint when running go test:
./mergesort.go:6: non-constant array bound leftLength
./mergesort.go:7: non-constant array bound rightLength
I assume go does not enjoy users instantiating an Array's length with a calculated value. It only accepts constants. Should I just give up and use a slice instead? I expect a slice is a dynamic array meaning it's either a linked list or copies into a larger array when it gets full.
You can't instantiate an array like that with a value calculated at runtime. Instead use make to initialize a slice with the desired length. It would look like this;
left := make([]int, leftLength)

How to remove the last element from a slice?

I've seen people say just create a new slice by appending the old one
*slc = append(*slc[:item], *slc[item+1:]...)
but what if you want to remove the last element in the slice?
If you try to replace i (the last element) with i+1, it returns an out of bounds error since there is no i+1.
You can use len() to find the length and re-slice using the index before the last element:
if len(slice) > 0 {
slice = slice[:len(slice)-1]
}
Click here to see it in the playground
TL;DR:
myslice = myslice[:len(myslice) - 1]
This will fail if myslice is zero sized.
Longer answer:
Slices are data structures that point to an underlying array and operations like slicing a slice use the same underlying array.
That means that if you slice a slice, the new slice will still be pointing to the same data as the original slice.
By doing the above, the last element will still be in the array, but you won't be able to reference it anymore.
If you reslice the slice to its original length you'll be able to reference the last object
If you have a really big slice and you want to also prune the underlying array to save memory, you probably wanna use "copy" to create a new slice with a smaller underlying array and let the old big slice get garbage collected.

Resources