連想配列

D言語の連想配列について
0
大堀龍一 (Ryuichi OHORI) @__DaLong

あれっ、通ったコードにバグ見つけた気がするんだけど、通ったってことはもしかして…

2012-06-16 23:19:28
大堀龍一 (Ryuichi OHORI) @__DaLong

@__DaLong D言語偉い。int[int] 連想配列は = 0 せずに += するだけでカウントアップできる。つまり暗黙の初期値0が入ってる。#D_lang

2012-06-16 23:26:23
hara kenji @9rnsr

これはint.initが0なため。double,floatの場合はnanになるので注意 RT @__DaLong: @__DaLong D言語偉い。int[int] 連想配列は = 0 せずに += するだけでカウントアップできる。つまり暗黙の初期値0が入ってる。#D_lang

2012-06-17 02:50:49
大堀龍一 (Ryuichi OHORI) @__DaLong

@9rnsr おお、そのうち (連想配列でないところで) double 初期化しないでひどい目に遭いそうです。

2012-06-17 02:56:24
kinaba @kinaba

@9rnsr @__DaLong これってdefined behaviorなんでしょうか。dmd だと int[int] x; int n=x[0]+1; が例外なのに x[0]=x[0]+1; が通るのですがバグのような気がしていて、x[0]+=1も同様にたまたまと疑ってました

2012-06-17 02:55:41
大堀龍一 (Ryuichi OHORI) @__DaLong

正しいかどうかはともかく、Python で dict を継承して default 値をもつ dect を作ってたこともあるし、便利ではある。その点では他所へ値を出すのはバグの元だからよくなくてカウントアップだけに使えるのはよいが、定義されてるかっていうと怪しいなあ。

2012-06-17 03:01:36
kinaba @kinaba

少なくとも昔はC++のstd::mapと同じ、なかったら.initを埋める仕様だったのを、読み取りのときは例外飛ばすことにある時点で変えた議論は記憶にあって、http://t.co/kN5Jihow でも例外のこと書いてない…。

2012-06-17 03:02:09
kinaba @kinaba

しかしサンプルに ++dictionary[word.idup] とか思いっきりあるなあ

2012-06-17 03:02:26
hara kenji @9rnsr

@kinaba @__DaLong あー、そうか意味的にはx[0]を初期化する前に操作する挙動になるのか。すいません、Dではx[0]に値を代入する前に読み出すのはRangeErrorが投げられます。

2012-06-17 03:03:13
SHOO @mono_shoo

@kinaba @9rnsr @__DaLong バグのような。まだ登録されていないキーを使っているので、RangeErrorが正しいような気がしますね。

2012-06-17 03:05:11
kinaba @kinaba

@mono_shoo @9rnsr @__DaLong (しかし今の動作の方が圧倒的に便利で自分としては好きなんですよねえ…)

2012-06-17 03:06:27
hara kenji @9rnsr

ただここで現在の実装では動いてしまう場合があって、x[0]=yyy、x[0]op=yyyの場合は左辺の評価で「値を代入するための領域を確保」してしまうため、右辺の評価時には例外が飛ばない、ということが起きます。

2012-06-17 03:06:39
hara kenji @9rnsr

限りなくバグに近い挙動なのですが、一応今の実装では確実に動いてしまうんですよね。bugzillaに登録されていたかな…?

2012-06-17 03:09:17
SHOO @mono_shoo

実害がないバグで、治すと既存コードを壊す可能性があって、しかも治った結果使いづらくなるバグ修正は果たしてするべきなのか…?

2012-06-17 03:09:26
hara kenji @9rnsr

@kinaba 値がまだないときは指定されたデフォルト値を返す、getという組み込みプロパティは一応すでにありますが… http://t.co/zb1RGOwG このデフォルト値が省略時にValue.initになったらいいのかな?

2012-06-17 03:11:28
SHOO @mono_shoo

@9rnsr 仕様書に、「x[0]=yyy、x[0]op=yyy で値を代入するための領域がない場合は、新しく領域をT.initの初期値の値で確保します。」って追加するのがいいのかなぁ。

2012-06-17 03:14:18
hara kenji @9rnsr

@mono_shoo 要素を格納する領域確保のタイミングが「代入の直前」ではなく「左辺値の評価時点(=右辺値の評価前)」なのが問題ですから、ある意味ここだけ非直感的な評価順序になってしまっているのを仕様にするのはちょっとためらわれますね。

2012-06-17 03:19:44
kinaba @kinaba

@9rnsr getはrefでもなくデフォルト値をついでにセットしたりもしないので、x.get(i, int.init)+=1; ができないので、それではあまり嬉しくなさそうです。x[i]=x.get(i(,0))+1 と書かないといけないなら ,0 がなくても大差ないかも

2012-06-17 03:25:46
SHOO @mono_shoo

@9rnsr そうですね。代入式は = の右の式が最初に評価される…って実は仕様ではないのですが、a[0] = a[0] + 1;がエラーにならないのはとても非直感的。

2012-06-17 03:26:26
SHOO @mono_shoo

s/エラーにならないのは/RangeErrorを投げないのは/

2012-06-17 03:28:00
hara kenji @9rnsr

@kinaba あー、getは左辺値を返さないのか。ただ現状getはobjectモジュールのAssociativeArrayテンプレートで定義されるので、これがrefで値を返すように変更することは出来ると思います。既存コードも壊れませんし。

2012-06-17 03:29:10
SHOO @mono_shoo

@9rnsr え、それって aa.get(key) のkeyがaaに存在しない場合、aa[key]が存在しないままValue.initが返されますが、その場合は何をrefで返すのです?

2012-06-17 03:31:57