Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
基礎からの Code Contracts
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Yoshifumi Kawai
May 23, 2011
Technology
91
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
基礎からの Code Contracts
Yoshifumi Kawai
May 23, 2011
More Decks by Yoshifumi Kawai
See All by Yoshifumi Kawai
.NET for Android with Native AOT Built with Cursor
neuecc
0
710
CysharpのOSS群から見るModern C#の現在地
neuecc
2
42k
R3のコードから見る実践LINQ実装最適化・コンカレントプログラミング実例
neuecc
5
56k
.NETの非同期戦略とUnityとの相互運用
neuecc
3
56k
他言語がメインの場合のRustの活用法 - csbindgenによるC# x Rust FFI実践事例
neuecc
7
41k
Modern High Performance C# 2023 Edition
neuecc
4
16k
CEDEC 2023 モダンハイパフォーマンスC# 2023 Edition
neuecc
9
120k
C#11 による世界最速バイナリシリアライザー「MemoryPack」の作り方
neuecc
1
42k
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
neuecc
1
500
Other Decks in Technology
See All in Technology
失敗を経て、Harness Engineering で 大切にしたいことを考える / Learning from Failure: What Matters in Harness Engineering
bitkey
PRO
1
370
MUSUBI 田中裕一『AIと共に行う「しごとのリデザイン」- スモールバックオフィス編』AI Ops Lab #4
musubi
0
190
中期計画、2回作ってみた ~業務委託と正社員、両方の視点から~
demaecan
1
860
AI駆動開発を通して感じた、 AI時代のデザイナーの役割変化
whisaiyo
3
2.1k
入門!AWS Blocks
ysuzuki
1
130
SONiCで構築・運用する生成AI向けパブリッククラウドネットワーク ~実装編~
sonic
0
210
不要なレビューをAIにまかせて AIコーディングの環境改善を加速した
shoota
1
110
AAIFに入ってみた ~内から見えるコミュニティ動向~
sato4
0
240
気軽に使える"情報のハブ"としてのNotion活用 〜フロー情報の集積点 と、 Claude Code × Notion AI〜
syucream
1
130
現地で盛り上がった WWDC26 Keynote
zozotech
PRO
1
250
LLMにもCAP定理があるという話
harukasakihara
0
380
小さくはじめるSLI/SLO ~育てながら組織に定着させる実践知~ / Starting Small with SLI/SLOs: Building Adoption Through Continuous Growth
nari_ex
7
1.9k
Featured
See All Featured
The Limits of Empathy - UXLibs8
cassininazir
1
360
Un-Boring Meetings
codingconduct
0
310
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
160
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
1
190
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.3k
Navigating Team Friction
lara
192
16k
The agentic SEO stack - context over prompts
schlessera
0
820
Joys of Absence: A Defence of Solitary Play
codingconduct
1
390
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
65
55k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
470
Transcript
基礎からの Code Contracts @neuecc – 2011/5/23
Twitter => @neuecc Blog => http://neue.cc/ HNは"neuecc"
読むときは“のいえ”で ⚫ ドメイン繋いだだけで特に意味はなく発音不能のた め(ccは声に出しにくいのでスルーという適当対応) Microsoft MVP for Visual C#(2011/4-) 公開してるライブラリとか ⚫ linq.js ⚫ DynamicJson ⚫ Chaining Assertion ⚫ DbExecutor <- (ちょっとだけ)Code Contracts使った Profile
First Step
.NET4から標準搭載された? mscorlibにSystem.Diagnostics.Contracts (主に)その中のContractクラスのメソッド群 Code Contracts
よくあるnullチェックをしてみようと思った ⚫ Contract.Requiresは事前条件 ⚫ 引数がnullだったら契約違反という感じにしたい static void Hoge(string arg)
{ Contract.Requires(arg != null); } が、実行しても無反応 Conditional属性がついているのでコンパイル時に 消える(条件付きメソッド、DEBUGとかでお馴染み) ⚫ 条件はCONTRACTS_FULL(但し自分で足す意味はない) 何か動かないよ?
よくあるnullチェックをしてみようと思った again ⚫ Contract.Requires<TException>も事前条件 ⚫ 引数がnullだったら契約違反で例外ぶん投げたい static void Hoge(string
arg) { Contract.Requires<ArgumentNullException>(arg != null); } が、変なアサートが飛ぶ そしてアプリは強制終了 リライターがmustだと? 何か動かないよ? Part2
Code Contractsの利用にはリライターが必要 最終的な配布物はコンパイラオプションで契約用コードを 取り除く。従って実行効率にも影響しない。 http://ja.wikipedia.org/wiki/契約プログラミング 契約は取り除かれなければならない そのためにはライブラリだけでは不可能で、コン
パイル時にバイナリを弄る必要がある 契約の実現のため、現状はバイナリ改変している ⚫ 真に標準搭載されたと言えるのはリライターがコン パイラと統合された時かもね つまるところ
必須 ⚫ Contractクラスなどコードに記述するマーカー ⚫ .NET 4で現状標準搭載されているのはこれだけ ⚫ バイナリリライター(ccrewrite.exe)
オプション ⚫ 参照ライブラリ生成(ccrefgen.exe) ⚫ ドキュメント生成(ccdocgen.exe) ⚫ 静的チェッカー(cccheck.exe) ⚫ cccheckはPremium Editionのみ ⚫ 静的チェックなしの場合は、例外orアサートを投げる実 行時チェックという形になる Code Contractsの構成物
Get Ready to Contracts
DevLabs: Code Contracts http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx Standard Edition (Visual Studio
Professional) ⚫ ccrewrite, ccrefgen, ccdocgen Premium Edition (Visual Studio Premium,Ultimate) ⚫ Standard + cccheck Visual Studio Express Editionでは使えない 静的チェッカーの有無も大きなところ ⚫ 契約の正しさが実行時じゃないと確認出来ないとい うのは、何が正しいのか分からない初学者にとって 学習が困難になる Code Contractsのインストール
に、Code Contractsタブが追加されてる チェックボックスをオンにすると各機能が有効に パラメータがいっぱいあって困る? ⚫ マニュアルを見れば勿論、説明がある ⚫
日本語で?zeclさんのスライドを見よう! ⚫ http://d.hatena.ne.jp/zecl/20110213/p2 プロジェクトのプロパティ
Contract.Requires ⚫ 無印と<TException>とEndContractBlockの三種 ⚫ 無印はコンパイラ生成のContractExceptionを投げる ⚫ コンパイラ生成なので型判別したcatchは不可能 ⚫ <TE>の場合は指定した例外を投げる
⚫ EndContractBlockはif-then-throwを<TE>に変換する // これと if (arg == null) throw new ArgumentNullException("arg"); Contract.EndContractBlock(); // これは大体等しい Contract.Requires<ArgumentNullException>(arg != null); 事前条件
EndContractBlockはレガシー環境用 ⚫ バイナリリライターがある環境が前提なら不要 Assembly Modeの選択 ⚫ Requires, Requires<TE>はStandard
Contract ⚫ EndContractBlockを使う場合はCustom Parameter 無印と<TE>ではリライト時に残るレベルが違う ⚫ 無印の場合はReleaseRequiresでは除去される DebugはFull、ReleaseではPreまたはReleaseを推奨 事前条件の違い
事後 : Contract.Ensures ⚫ 戻り値を表すContract.Result<T>とセットで使うこと が多い 不変 :
Contract.Invariant ⚫ ContractInvariantMethod属性とセットで ⚫ cimコードスニペットを使えば展開される インターフェイスへの契約 ⚫ 書くのがヘンテコで面倒くさい ⚫ cintfコードスニペットを使えば展開される 事後・不変・インターフェイス
Marriage with IntelliSense
静的チェッカなしだと、どうも地味 ⚫ Premiumの人なら関係ないですねShit! そんな物足りなさを感じるアナタにVisualな贈り物 VS拡張:Code Contracts Editor
Extensions http://visualstudiogallery.msdn.microsoft.com/85f0aa38 -a8a8-4811-8b86-e7f0b8d8c71b 契約がIntelliSenseに表示される! FreeなのでVS Professionalの人でもOK 動かしたけど嬉しさ少なめ?
.NET4からBCLも契約済み ⚫ そういう意味では標準搭載と言えなくもない おや、標準ライブラリの様子が
標準ライブラリは何もしなくても表示される 自作の契約はReference Assemblyを作る必要がある Reference Assemblyはクラスライブラリなど、契約 が除去されたリリース用バイナリを参照する他の ライブラリが契約情報を参照したい場合に必要
(但し、決してリライト後のバイナリに契約を再 度埋め込めれるわけではない) 使い方
コンストラクタは表示されません ジェネリックメソッドは表示されません ⚫ Enumerable.Rangeは表示されるのにRepeatは表示さ れなかったりしてるのが確認できます ⚫ つまるところLINQのメソッドは全滅
yieldが含まれると表示されません dynamicが含まれると表示されません よく落ちます(落ちたらVS再起動まで復活しない) Editor Extensionsに関してはアルファ版だと思って 暖かく見守りましょう 但し制限も色々あり
Merit and Demerit
引数名を文字列で指定しなくてもいい ⚫ リライターが埋め込んでくれるから ⚫ コードスニペットcrenは文字列指定付きだけど、個 人的にはそれは不要だと思う // この文字列で引数名を書くのがかなりイヤだった if
(arg == null) throw new ArgumentNullException("arg"); // それをCode Contractsではこう書き、そしてこれは Contract.Requires<ArgumentNullException>(arg != null); // バイナリリライト後にこうなる // 最後の"arg != null"がメッセージで、 // 条件を文字列として生成してくれているのが分かる __ContractsRuntime.Requires<ArgumentNullException>( arg != null, null, "arg != null"); 嬉しいこと1
インターフェイスに契約すると、それを実装する ものへは何も書かなくても自動で埋め込まれる // こうしてインターフェイスへの契約を作ると(cintfスニペット推奨) [ContractClass(typeof(IHogeContract))] public partial interface IHoge
{ void Show(string arg); } [ContractClassFor(typeof(IHoge))] abstract class IHogeContract : IHoge { public void Show(string arg) { Contract.Requires<ArgumentNullException>(arg != null); } } 嬉しいこと2
class ClassA : IHoge { // 何も書いていませんが // Contract.Requires<ArgumentNullException>(arg !=
null)が埋めこまれる public void Show(string arg) { Console.WriteLine(arg); } } class ClassB : IHoge { // 全てのメソッドにif(arg == null) throwを書く時代さようなら! public void Show(string arg) { Console.WriteLine(arg + arg); } } これにより、積極的なインターフェイスの抽出と 契約の記述が促されます(不純動機ドリブン) それはとっても嬉しいなって
静的チェッカーでTester-Doerパターンを安全に // こんなどうでもいいクラスがあるとして public class ToaruClass { int value;
public bool IsReadOnly { get; private set; } public void SetValue(int value) { Contract.Requires(!IsReadOnly); this.value = value; } } var toaru = new ToaruClass(); // IsReadOnlyをチェックしていないのでunproven toaru.SetValue(100); // こう書けばSafe if (!toaru.IsReadOnly) toaru.SetValue(100); 嬉しいこと3
Requiresで検証する要素は外部から見えないと、バ イナリリライターを通りません public class ToaruClass { int value; private
bool isReadOnly; public ToaruClass(bool isReadOnly) { this.isReadOnly = isReadOnly; } public void SetValue(int value) { // isReadOnlyが外から不可視なのでダメ Contract.Requires(!isReadOnly); this.value = value; } } Requiresの基本
Requires、事前条件はメソッド呼び出し側が、正し い呼び出しが可能かの責任を負う必要がある、つ まり外から検証可能でないとならない 逆にEnsures、事後条件が正しく成立するかはメ ソッド側の責任なので、メソッド内部できちんと Ensuresの条件が満たせる必要がある なんでなんで?
Requires内で使えるメソッドはPureなもののみ ⚫ 警告なので実行は出来なくはない // Pureを付けないと警告が! [Pure] public static bool
IsNull(string arg) { return arg == null; } public void Hoge(string arg) { Contract.Requires(!IsNull(arg)); } Pure、つまり副作用ナシということ ⚫ String.IsNullOrEmptyなど当然Pure属性ついてます ⚫ Pureかどうかは自己申告制だったり(非Pureなもので も付けること自体は可能、勿論それはダメですよ) Requiresの基本 Part2
静的チェッカーは契約の連鎖で成り立っているの で、契約されてないライブラリが混じると警告祭 りになって鬱陶しい そういう場合はContract.Assumeで、契約済みを擬 態していくのだけど数が多いと心が折れる、だけ じゃなくコードが汚れて可読性悪化の一方に Typeの一部とかExpressionの一部とか、契約済みの
はずの標準ライブラリの中にも上手く動かないの がチラホラ 嬉しくないこと
// これは静的チェッカでunproven行き var func = typeof(Func<,>); var genFunc = func.MakeGenericType(typeof(int),
typeof(int)); // 警告を元に、こうAssumeすればいいんですがなんというかかんというか var func = typeof(Func<,>); Contract.Assume(func.IsGenericTypeDefinition); Contract.Assume(func.GetGenericArguments().Length == 2); var genFunc = func.MakeGenericType(typeof(int), typeof(int)); 例えばこんなunproven
// (object x) => (object)((T)x).name static Func<object, object> CreateGetValue(Type type,
string name) { Contract.Requires<ArgumentNullException>(type != null); Contract.Requires<ArgumentNullException>(name != null); // Expression.Unboxに事後条件非nullの契約がないため // Expression.PropertyOrFieldの引数が求めるrequires expr != null の検証に失敗する var x = Expression.Parameter(typeof(object), "x"); var func = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.PropertyOrField( (type.IsValueType) ? Expression.Unbox(x, type) : Expression.Convert(x, type), name), typeof(object)), x); return func.Compile(); } Unproven Hell
Expressionも基本的には契約されているんですが、 Expression.UnboxとかExpression.Assignと か、.NET4で新しく追加されたものはあまり契約さ れてないみたい なので山崎春のunproven祭り Expressionは基本的に引数に突っ込んで式としてツ リー上に組み立てていくものなので、Assumeする
のが難しい ⚫ もしAssumeするなら、全部バラして変数にしてから 組み立てなければならないけど、それはない どういうこと?
// 面倒くさくて耐え切れない時は静的検証オフ属性をつけてやる [ContractVerification(false)] static Func<object, object> Create(Type type, string name)
{ // (中略) } Contract.Ensures(Contract.Result<T>() != null); がど れだけ大事かが身にしみて分かる ⚫ しかし定型句すぎて面倒くさいのは事実…… ⚫ cenコードスニペットがあるとはいえ そして平穏が訪れる
Conclusion
.NET4標準に入っているContractsライブラリの他に、 幾つか追加の属性が C:¥Program Files (x86)¥Microsoft¥Contracts¥Languages¥CSharp に ある(.csファイルぽん置き) ⚫ 使い方の詳細はマニュアルに載ってる
Microsoft Researchで開発されている自動パラメタ ライズドテストPexに対してContractsが記述されて いると、有効な自動生成パラメータが生成できる ようになる http://research.microsoft.com/en-us/projects/pex/ その他
メリットを幾つかあげましたが、忘れてはならな い基本的なことは、「事前・事後・不変」の契約 が出来るということ でも、堅苦しい理屈だけじゃなく、目で見て分か る実用的な便利さを提供してくれるのはいいね! if-then-throwを撲滅してくれるというだけでも十 分嬉しいなって
まずはそこからで、徐々に高度にステップアップ すればいいんじゃないかな Expressで使えないのが痛い&Premium以上でない と静的チェッカーが使えないのが大変痛いので、 将来は何とかして欲しいと切実に願う まとめ