Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
基礎からの Code Contracts
Search
Yoshifumi Kawai
May 23, 2011
Technology
110
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
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
4
2.8k
.NET for Android with Native AOT Built with Cursor
neuecc
0
6.6k
CysharpのOSS群から見るModern C#の現在地
neuecc
2
47k
R3のコードから見る実践LINQ実装最適化・コンカレントプログラミング実例
neuecc
5
57k
.NETの非同期戦略とUnityとの相互運用
neuecc
3
56k
他言語がメインの場合のRustの活用法 - csbindgenによるC# x Rust FFI実践事例
neuecc
7
42k
Modern High Performance C# 2023 Edition
neuecc
4
16k
CEDEC 2023 モダンハイパフォーマンスC# 2023 Edition
neuecc
9
120k
C#11 による世界最速バイナリシリアライザー「MemoryPack」の作り方
neuecc
1
42k
Other Decks in Technology
See All in Technology
Genieを崇めよ
kameitomohiro
0
170
Issue 駆動でスペシャリストの意図を届ける、AI 実装のアクセシビリティ向上
thkt
0
120
C#未経験の僕がAIに読めるコードを書かせるまで
maguroalternative
0
110
Reactの設計論
uhyo
24
14k
EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ / No Join in EventBridge
yusukeshimizu
2
290
AIエージェントの自己改善をどう設計するか / How to Design Self-Improvement for AI Agents
22mi
25
16k
顧客に向き合う開発組織へ。リアーキテクチャとフィーチャーチーム化で挑む組織改革
safie
0
2.1k
データ_AIの事業の勝敗をわけるもの
nek0128
1
460
Claude in Chrome 入門 / Introduction to Claude in Chrome
cielo1985
0
870
AIは推し活である。
kurazuuuuuu
1
860
技術的負債から考える、AI時代のエンジニアリング投資 — ビズリーチの技術的負債と向き合った経験から、変更し続けられるソフトウェアを考える/ technical-debt-con2026
visional_engineering_and_design
4
3.3k
越境するなら専門用語を使うな高校校歌 / If you wanna cross border, you shouldn't use jargon
vtryo
0
150
Featured
See All Featured
Un-Boring Meetings
codingconduct
0
420
Rails Girls Zürich Keynote
gr2m
96
14k
The SEO identity crisis: Don't let AI make you average
varn
0
560
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
57k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.1k
BBQ
matthewcrist
89
10k
sira's awesome portfolio website redesign presentation
elsirapls
0
420
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
The Spectacular Lies of Maps
axbom
PRO
1
1k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
690
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.6k
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以上でない と静的チェッカーが使えないのが大変痛いので、 将来は何とかして欲しいと切実に願う まとめ