バリアントの真実

2
ほえほえ@スプシマン @hoehoe1234

本日の勉強会発表資料。自己紹介のつかみ。あまり受けなかった。。。。(自爆 pic.twitter.com/Gc7Hn2f30r

2020-03-21 17:58:06
拡大
ほえほえ@スプシマン @hoehoe1234

改善さんがフォローしてくれなかったらエライことになっていたかもしれん。。。VBAの簡単な説明、変数の型、バリアントについて先に説明していただいた。その場での改善さんのアドリブ。すげーw。 pic.twitter.com/P0yGL3Uf9J

2020-03-21 17:59:58
拡大
ほえほえ@スプシマン @hoehoe1234

用語の解説。現場猫はこれが好き。滝Libのアイデアの殆どはパイソンのパクリですwww。 pic.twitter.com/huHH9uf12T

2020-03-21 18:01:14
拡大
ほえほえ@スプシマン @hoehoe1234

ワイは!バリアント型の濡れ衣を!晴らすときは!今!。 ですが、さらっと流しました。。。。。 pic.twitter.com/Qq3OyfvC7J

2020-03-21 18:02:54
拡大
ほえほえ@スプシマン @hoehoe1234

それとなく自分語りさっくりと。ワイのバリアント型を使うようになった経緯が相当美化されて記載されています。ほんとは長々と書くのがめんどくさくしゃーなかったんです、、、、。 pic.twitter.com/umsPmX9bZp

2020-03-21 18:05:56
拡大
ほえほえ@スプシマン @hoehoe1234

つかみで使ったロシアン寿司屋のコード紹介。3人が寿司屋で注文して「河豚」があたったらおしまいというプログラムを題材に「バリアントの美しさ」を語りました。実際このコードに型指定はまったくありません。 pic.twitter.com/d2clUIBqFY

2020-03-21 18:08:10
拡大
ほえほえ@スプシマン @hoehoe1234

ロシアン寿司屋ではプログラミング自体ではなくて「バリアント型」しか使ってないことを説明しました。実行するとだいたい3人のうちのだれかが河豚を食べて死にます。 pic.twitter.com/imnTjSKtrd

2020-03-21 18:12:26
拡大
ほえほえ@スプシマン @hoehoe1234

あまり説明できませんでしたがこの図は重要です。通常変数への代入は「変数への値の代入」となりそれぞれの変数の型は代わりません。バリアント型では変数の代入時に代入元の変数の「型」も同時に設定しています。これがバリアントには明確な型がありその型は動的に設定されるということです。 pic.twitter.com/zf9T5l9uTV

2020-03-21 21:32:35
拡大
ほえほえ@スプシマン @hoehoe1234

①具象型同士の代入 a = b aとbの型は代入前後で変わりません。そのまま代入できない場合は暗黙の変換が行われます(文字列型に数字を代入したような場合など) ②バリアント型へ具象型の代入 v = b bの型がバリアント型の型情報として設定されます。これによりvは評価するとと型bの挙動を示します。 pic.twitter.com/s5dvsYUz14

2020-03-21 23:44:40
拡大
ほえほえ@スプシマン @hoehoe1234

この図をよく見てください。具象型のcon_strに99を代入すると文字列の"99"に暗黙の変換が行わています。is系の関数の判定結果を見てください。vari_strにも99を代入したのでvari_strはInteger型の変数として振る舞います。これはis系の評価かな数を実行できることで評価結果を予想できます。

2020-03-21 23:46:50
ほえほえ@スプシマン @hoehoe1234

すなわち ①v = aというバリアント型変数への具象型変数の代入時には具象型の型を含めて代入が行われます(すなわち暗黙の型変換は起こりません。なぜなら代入元と同じ型になるからです。かつそれに必要な十分な領域がバリアント変数にはあります)。

2020-03-21 23:49:31
ほえほえ@スプシマン @hoehoe1234

②a = vという具象型変数へのバリアント型変数の代入時には代入先の変数の型は変わらないので必要があれば暗黙の型変換が行われます。代入元のバリアント型変数はバインドされている型の変数のように振る舞います。この図でいえばString型変数にInteger型変数の値を代入するように振る舞います。 pic.twitter.com/fzjqLBkNSD

2020-03-21 23:55:17
拡大
ほえほえ@スプシマン @hoehoe1234

③v2 = v1というバリアント型同士の代入はどうなるでしょうか?結果はコピー先の変数にコピー元の変数の型が設定されます。これはv = a(具象型)の変形と考えて良いでしょう。コピー元のバリアント変数はバインドされた型の変数のように振る舞うので v2 = (v1バインドされた型評価)となります。 pic.twitter.com/5aMKlriXXq

2020-03-22 00:04:08
拡大
ほえほえ@スプシマン @hoehoe1234

これについてはバリアント同士の代入なので「そのまま型フィールドを含めて代入される」と考えても良いのですが後述するバリアントの型の4つのタイプの考察から「コピー元のバリアントをバインドされた型とみなして評価」して評価結果の型と値が設定されるとみるのが妥当だと考えます。

2020-03-22 00:05:49
ほえほえ@スプシマン @hoehoe1234

また、バリアントには変数の状況に応じたタイプ(値の型といういみではありません)があります。これらは「①単純型、②(単純型に対する)参照型、③(単純型の)配列型、④配列参照型」に分類できます。これがバリアン型の挙動理解に最も重要な知識・概念となります。 pic.twitter.com/GCxtGzVEbC

2020-03-22 01:46:30
拡大
ほえほえ@スプシマン @hoehoe1234

バリアント型の大きさは16バイトです。そのうちの半分の8バイトが値の格納に使われます。値型で最も大きいのはカレンシー型を除くと8バイトですので縮小変換することなくそのまま保持できます(カレンシー型の場合は予約領域も使われます。)。なににしろ、結局、型変換は起きません。

2020-03-22 01:58:04
ほえほえ@スプシマン @hoehoe1234

これを私は「型をバインド(結束)する」と呼んでいます。具象型変数をバリアント型変数に代入した場合は、元の変数の型がバリアント変数にバインドされ、その値はバリアント変数の値フィールドにそのままコピーされることになります。型情報と値情報の両方を変数内にもっているとも言えます。

2020-03-22 02:00:52
ほえほえ@スプシマン @hoehoe1234

具象型の型情報はVBAのランタイム(インタプリター)が内部情報として保有しています。プログラマーはこれを変更したり参照したりはできません。しかし、バリアント型変数は型情報が変数の一部として外だしされているのでこれにアクセスすることができ、かつ、動的に変更可能となっています。

2020-03-22 02:02:36
ほえほえ@スプシマン @hoehoe1234

ではこの4つのタイプを示していきます。まず通常の変数を含めて変数がどのような構成になっているのかを説明します。 ①文字列はBSTRという文字列領域への参照になっています。BSTRに関してはこのサイトでイメージをつかんでください。 keicode.com/com/bstr-alloc… pic.twitter.com/PXeQiLWrXw

2020-03-22 10:11:53
拡大
ほえほえ@スプシマン @hoehoe1234

実際にBSTR領域をダンプしてみます。たしかに4バイトの文字列長領域と実際の文字が2バイト単位で格納されています。メモリ操作にはMoveMemory関数を使用します。この関数はVBAの構造を知るために必須となりますのでマスターしてください。これで文字列のイメージはつかめたでしょうか? pic.twitter.com/YEtTKRR81B

2020-03-22 10:41:37
拡大
拡大
ほえほえ@スプシマン @hoehoe1234

文字列型変数のまとめ ①文字列型変数サイズは4バイトでありその値はBSTRへの参照(ポインタ)となっている。 ②にも関わらず文字列型変数は値型として扱える(代入すると新しいBSTR領域が確保されるという意味) ③文字列型変数の内容(参照値)はMoveMemory関数で取得し、Long型変数に代入できる。

2020-03-22 10:44:57
ほえほえ@スプシマン @hoehoe1234

次の配列の説明をします。VBAでは配列はSAVEARRAYというものを使用しています。サイズチェックのある便利な配列です。先に参考URLを示します。 docs.microsoft.com/ja-jp/windows/… bytecomb.com/vba-internals-… docs.microsoft.com/ja-jp/previous… www5f.biglobe.ne.jp/~f-lap/tips_st… marupeke296.com/IKDADV_CPP_SAF… docs.microsoft.com/ja-jp/cpp/atl/…

2020-03-24 03:11:24
ほえほえ@スプシマン @hoehoe1234

配列は値型として振る舞いますが、配列型変数の実態は4バイトで参照(SA構造体へのポインタ)を格納するようになっています。文字列型と同じですね。構成は①配列変数->②SA構造体(配列の次元、要素数、要素サイズの情報)->③実データ領域 という参照関係になっています。結構複雑ですね。

2020-03-24 03:15:24
ほえほえ@スプシマン @hoehoe1234

では配列の実態を知るために配列の情報を出力してみましょう。バリアントが一番威力を発揮するのは配列に対する操作ですのでじっくりと理解しましょう。 pic.twitter.com/QwvvE0HpnJ

2020-03-24 03:17:21
拡大
ほえほえ@スプシマン @hoehoe1234

参考のためにSA構造体の前半部分のコードを提示しておきます。この関数は ①tk_safearr_addr関数でSA構造体のアドレスを取得 ②そのアドレスからSA構造体の各フィールドの値を出力 を行っています。 pic.twitter.com/aCMHravSRr

2020-03-24 03:22:12
拡大