Erhan Yakut Software Developer @Binalyze | Founder @Passwall | Golang Enthusiast | Open Sorcerer

Go’da Empty Struct Karşılaştırma Problemi

2 min read

Yazılım geliştirirken bazen anlam veremediğimiz durumlarla karşılaşırız. Her programlama dilinde olduğu gibi Go’da da özenle işlenmesi ve açıklanması gereken konular vardır. Bunlardan birisi de boş (empty) struct’ların karşılaştırılmasıdır.

Soru

Öncelikle aşağıda gördüğünüz basit kodun çıktısı false‘tur. Buna göre bir fonksiyon içinde tanımlanan aynı tipe sahip iki boş struct “==” ile karşılaştırıldığında (compare) birbirinden farklı görünüyor.

Kodda ufak bir değişiklik yapıp karşılaştırma (compare) işleminden önce değişkenleri ekrana yazdırıyoruz. Bu sefer karşılaştırma sonucu ilginç bir şekilde true oluyor.

Çıktıda gördüğünüz gibi ilgili değişkenlerin pointer’ları aynı olmasına rağmen neden ilk seferinde sonuç false iken ikincisinde true‘dur?

Cevaplar

Bu paragrafın başlığı farkettiyseniz Cevap değil Cevaplar çünkü yukarıdaki soruyu cevaplamak için birkaç şeyi bilmek gerekiyor.

1. Öncelikle Versiyon 1’de söz konusu boş stuct’a sahip değişkenler stack‘te bulunmaktadır. Versiyon 2’de değişkenler fmt.Printf fonksiyonuna gönderilmektedir. fmt.Printf, interface{} kabul eden bir fonksiyondur ve kendi içinde reflect kullanarak verileri işleme sokar. Böyle bir durumda stack’ten heap’e kaçma (escape) durumu gerçekleşir. Bunu Versiyon 2’de escape analizi komutu çalıştırarak görebiliriz.

$ go run -gcflags="-m -l" main.go
# command-line-arguments
./main.go:8:7: &Foo{} escapes to heap
./main.go:9:7: &Foo{} escapes to heap
./main.go:11:12: ... argument does not escape
./main.go:12:12: ... argument does not escape
./main.go:14:13: ... argument does not escape
./main.go:14:16: a == b escapes to heap
0x1025330f8
0x1025330f8
true

Not: Go’da allocation’lar ve stack ile heap kavramını daha iyi anlamak için Memory allocations in Go makalesini okuyabilirsiniz.

2. Go’nun derleyicisi yani compiler‘da oldukça fazla optimizasyon söz konusudur. Bunlardan birisi de heap’teki bütün 0-byte allocationlar yani boş struct, slice vb. yapılar için runtime paketindeki zerobase adresi (runtime.zerobase) kullanılmasıdır. Elbette bunu yaparak gereksiz memory allocation’ların önüne geçmek hedeflenmiştir. Bunun sonucunda tüm boş yapılar aynı adresi gösterebilir (veya göstermeyebilir! birazdan değineceğim.). Heap’a kaçma durumlarında boş struct’lar aynı adresi gösterdiği için de Versiyon 2’deki karşılaştırma işlemi “true” ile sonuçlanmaktadır.
// runtime/malloc.go
var zerobase uintptr

3. Versiyon 1’de ise durum biraz daha farklıdır. Go dilini geliştiren kişiler tarafından bilinçli olarak tercih edilen bir davranış söz konusudur. Stack’teki boş struct karşılaştırma işlemlerinde optimizasyon amacıyla hiç karşılaştırma yapılmadan yani yapılar aynı mı diye bakılmadan doğrudan false dönülür. Bunun sebebini de şöyle açıklanmaktadırlar.

This is an intentional language choice to give implementations flexibility in how they handle pointers to zero-sized objects. If every pointer to a zero-sized object were required to be different, then each allocation of a zero-sized object would have to allocate at least one byte. If every pointer to a zero-sized object were required to be the same, it would be different to handle taking the address of a zero-sized field within a larger struct.

Ayrıca Go Spec‘inde şöyle belirtilmektedir.

Pointers to distinct zero-size variables may or may not be equal.

Son Sözler

Görüldüğü gibi her ilginç durumun arkasında hiç hesaba katmadığımız kasıtlı bir davranış olabiliyor (veya sadece bug’dır :)) Yine de buradan çıkarmamız gereken ders, boş struct’ların karşılaştırılmasının sakıncalı olması nedeniyle bu işlemden uzak durmak gerektiğidir. Bir sonraki Go çıkmazında görüşmek dileğiyle.

Kaynaklar

Erhan Yakut Software Developer @Binalyze | Founder @Passwall | Golang Enthusiast | Open Sorcerer

Go Programlama Dili’ni Nasıl Öğrenebilirim?

Her gün çevremde Go Programlama Dili‘ni merak eden ama nasıl ve nereden başlayacağını bilemeyen birçok kişiyle karşılaşıyorum. Twitter mesaj kutum da bu konuların sorulduğu...
Erhan Yakut
3 min read