これは何?
Go は Java ほど write once, run anywhere ではないことは知っているけど、どこで実装依存になるのかを知らなかったので調べてみた。
まあ unsafe なやつは含めなかった。
情報源はすべて The Go Programming Language Specification - The Go Programming Language である。
int, uint, uintptr のサイズ
まあこれは有名だよね。
C/C++ と違って、int
, uint
のサイズは 32 または 64 ビット。
16 ビットだったり 40ビットだったりする可能性はない。
一方、uintptr
は「ポインタを格納できるサイズ」としか決まっていない。文章を見る限り、40ビットとかの可能性を排除していないように見える。
浮動小数点数の周辺
浮動小数点数から他の数値型への変換
In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.
とあるので、2の100乗などの float64, float32 を整数に変換した場合などの動作が実装依存。
ゼロ除算の振る舞い
The result of a floating-point or complex division by zero is not specified beyond the IEEE-754 standard; whether a run-time panic occurs is implementation-specific.
浮動小数点数のゼロ除算で panic になるのかそれ以外のなにか(たぶん、非数)になるのかは実装依存。
非数になっても大丈夫なように対応していたら、特定のアーキテクチャでまれに panic が起こり、手元の環境では再現しないなぁ、みたいな事がありえる模様。
サイズヒントつきで map を作る場合
Calling make with a map type and size hint n will create a map with initial space to hold n map elements. The precise behavior is implementation-dependent.
これは、直前の例
m := make(map[string]int, 100) // map with initial space for approximately 100 elements
のような、サイズヒントつき map
の話。サイズヒントを書くことはできるけど、そのサイズヒントが実際どんな効果をもたらすのかは実装依存ということだと思う。この文を見る限り、サイズヒントを無視する実装があっても許されそうに見える。
import のパス
The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled package and may be relative to a repository of installed packages.
とある。この文の ImportPath は、
import "fmt"
の "fmt"
の部分。
まあこれは処理系のファイルシステムに依存せざるを得ないので仕方ない。
Windows だと
import "net\\http\\httputil"
とか書けたりするのかなぁ(試してない)。
print の出す文字列
こんな
prints all arguments; formatting of arguments is implementation-specific
ことが書いてある。ここでいう print
は、fmt.Print
のことではなく go がちゃんと起動するまでに使われる関数のことらしい。普通のユーザは関係ない。
FMA とか適当に使うので計算結果が実装依存
some architectures provide a "fused multiply and add" (FMA) instruction that computes xy + z without rounding the intermediate result xy. These examples show when a Go implementation can use that instruction:
とある。FMA が使えるなら x*y+z
を一気にやってから丸めるし、使えないなら x*y
をやって、それを丸めてから z
を足して、もう一回丸める。
なので、丸め誤差の出方が変わるかもね、ということらしい。
数値計算の文脈だとわりと痛そう。
調べてないこと
ライブラリは調べてない。色々あると思う。time.Sleep
で寝られる時間とか明らかに実行環境依存。
chan
や goルーチンのタイミングとかも色々あると思う。
まとめ
ゼロ除算の振る舞いが実装依存なのはちょっとびっくりした。わりと嫌な罠として機能しそう。
範囲外の値から整数への変換結果が実装依存なのもびっくりした。 C++ みたいな速度に全振りの言語じゃないんだから、そこは振る舞いを揃えたほうが良かったんじゃないの、と思った。
FMA は、まあそうかなとも思うけど、それは困るという人もたくさんいるよね。