gcontractsの基礎
TRANSCRIPT
GContractsの基礎
Groovy基礎勉強会2013/03/09
13年3月11日月曜日
いいわけ13年3月11日月曜日
只今、仕事が絶賛デスマーチ中なので、内容はグダグダです。
13年3月11日月曜日
13年3月11日月曜日
詳細は「gdgd妖精s」でググって。
13年3月11日月曜日
お前誰よ•名前:杉浦孝博•twitter:@touchez_du_bois•自称アニメエヴァンジェリスト•最近はVB6とVB.NETがお友達
13年3月11日月曜日
閑話休題13年3月11日月曜日
今回の内容•契約による設計•GContractsとは•GContractsの実際
13年3月11日月曜日
1.契約による設計Design by Contracts
13年3月11日月曜日
契約による設計•プログラムコードの中にプログラムが満たすべき仕様についての記述を盛り込む事で設計の安全性を高める技法(Wikipediaより)。
13年3月11日月曜日
契約による設計•Bertrand Meyer氏の提唱•詳細はこんな本で
13年3月11日月曜日
契約による設計•コードの利用者と実装者の間の契約
•利用者側が守るべきこと•実装者が約束すること
13年3月11日月曜日
契約による設計•主ロジックとは別に、コードとして契約内容を定義
•コード利用の責任範囲を明確化
13年3月11日月曜日
契約による設計•契約の条件•事前条件(Precondtion)•事後条件(Postcondition)•不変条件(Invariant)
13年3月11日月曜日
契約による設計•事前条件•サブルーチンの開始時に満たされるべき条件
•呼び出し側が守ること13年3月11日月曜日
契約による設計•事後条件•サブルーチンの終了時に保証されるべき条件
•実装側が守ること13年3月11日月曜日
契約による設計•不変条件•公開している操作の実行後に常に保証されるべき条件
•実装側が守ること13年3月11日月曜日
詳しくは•原本で
13年3月11日月曜日
詳しくは•@t_wadaさんの• http://www.slideshare.net/t_wada/exception-design-by-contract#btnPrevious
13年3月11日月曜日
2.GContractsとはWhat’s GContracts
13年3月11日月曜日
言語標準な言語•Eiffel•Bertrand Meyer氏考案•D言語
13年3月11日月曜日
Java•標準•assert文•ライブラリ•Contract4J, cofoja
13年3月11日月曜日
Groovy•標準•assert文(PowerAssert)•ライブラリ•GContracts
13年3月11日月曜日
GContracts•Andre Steingress氏による契約プログラミング用のライブラリ
•https://github.com/andresteingress/
13年3月11日月曜日
GContracts•アノテーションにより満たすべき条件をコード中に記述
•条件のコード内容はGroovyDocに出力可能
13年3月11日月曜日
GContracts•事前条件 -> @Requires•メソッドに指定•事後条件 -> @Ensures•メソッドに指定•不変条件 -> @Invariants•クラスに指定
13年3月11日月曜日
GContracts•各条件をクロージャで記述•契約に違反した場合、PowerAssertでエラー出力
13年3月11日月曜日
GContracts•@Ensuresのクロージャ内では、次の値を参照できる
•old : メソッド実行前の状態。Map
•result : 実行結果13年3月11日月曜日
GContracts•各条件を継承•各条件をクラスだけでなくインタフェースにも指定可
13年3月11日月曜日
GContractsimport org.gcontracts.annotations.*
@Invariant({ speed() >= 0 })class Rocket { int speed = 0 @Requires({ isStarted() }) @Ensures({ old.speed < speed }) void accelerate() { ++speed }
boolean isStarted() { true } int speed() { speed }}
13年3月11日月曜日
3.GContractsの実際Actuals of GContracts
13年3月11日月曜日
やってること•3行で言うと...
13年3月11日月曜日
やってること•3行で言うと...•AST変換で
13年3月11日月曜日
やってること•3行で言うと...•AST変換で•条件用のコードを
13年3月11日月曜日
やってること•3行で言うと...•AST変換で、•条件用のコードを、•コンストラクタとメソッドに埋め込み
13年3月11日月曜日
やってること•3行で言うと...•AST変換で、•条件用のコードを生成、•コンストラクタとメソッドに埋め込み、•実行する。
13年3月11日月曜日
AST変換•Abstract Syntax Tree変換•抽象構文木をこねくりまわす
13年3月11日月曜日
AST変換•サービスプロバイダ機能を使って、次のASTTransformationの実装クラスを指定。
•org.gcontracts.ast.ClosureExpressionEvaluationASTTransformation
•org.gcontracts.ast.GContractsASTTransformation
13年3月11日月曜日
ClosureExpressionEvaluationASTTransformation
•Semantic Analysisフェーズで実行
•条件のクロージャ用のクラスコードを生成
13年3月11日月曜日
import org.gcontracts.annotations.*
@org.gcontracts.annotations.Invariant(value = Rocket$_gc_closure1)@org.gcontracts.annotations.Contractedpublic class Rocket extends java.lang.Object {
private int speed final static boolean $GCONTRACTS_ENABLED
@org.gcontracts.annotations.Requires(value = Rocket$_gc_closure2) @org.gcontracts.annotations.Ensures(value = Rocket$_gc_closure3) public void accelerate() { ++( speed ) }
public boolean isStarted() { true }
public int speed() { speed }}
13年3月11日月曜日
final public class Rocket$_gc_closure1 extends groovy.lang.Closure<V extends java.lang.Object> { // (省略) public java.lang.Boolean doCall() { java.lang.Boolean $_gc_closure_result = false try { assert this.speed() >= 0 : null $_gc_closure_result = true } catch (org.codehaus.groovy.runtime.powerassert.PowerAssertionError error) { org.gcontracts.ClassInvariantViolation newError = new org.gcontracts.ClassInvariantViolation('<org.gcontracts.annotations.Invariant> Rocket \n\n' + error.getMessage()) newError.setStackTrace(error.getStackTrace()) } finally { } return $_gc_closure_result } // (省略)}
13年3月11日月曜日
final public class Rocket$_gc_closure2 extends groovy.lang.Closure<V extends java.lang.Object> { // (省略)
public java.lang.Boolean doCall() { java.lang.Boolean $_gc_closure_result = false try { assert this.isStarted() : null $_gc_closure_result = true } catch (org.codehaus.groovy.runtime.powerassert.PowerAssertionError error) { org.gcontracts.PreconditionViolation newError = new org.gcontracts.PreconditionViolation('<org.gcontracts.annotations.Requires> Rocket.void accelerate() \n\n' + error.getMessage()) newError.setStackTrace(error.getStackTrace()) } finally { } return $_gc_closure_result }
// (省略)}
13年3月11日月曜日
final public class Rocket$_gc_closure3 extends groovy.lang.Closure<V extends java.lang.Object> { // (省略)
public java.lang.Boolean doCall(java.util.Map old) { java.lang.Boolean $_gc_closure_result = false try { assert old .speed < speed : null $_gc_closure_result = true } catch (org.codehaus.groovy.runtime.powerassert.PowerAssertionError error) { org.gcontracts.PostconditionViolation newError = new org.gcontracts.PostconditionViolation('<org.gcontracts.annotations.Ensures> Rocket.void accelerate() \n\n' + error.getMessage()) newError.setStackTrace(error.getStackTrace()) } finally { } return $_gc_closure_result }
// (省略)}
13年3月11日月曜日
GContractsASTTransformation
•Instruction Selectionフェーズで実行
•条件の実行コード生成し、コンストラクタやメソッドに追加する
13年3月11日月曜日
@org.gcontracts.annotations.Invariant(value = Rocket$_gc_closure1)@org.gcontracts.annotations.Contractedpublic class Rocket extends java.lang.Object {
private int speed final static boolean $GCONTRACTS_ENABLED
public Rocket() { this.invariant_Rocket() }
13年3月11日月曜日
@org.gcontracts.annotations.Requires(value = Rocket$_gc_closure2) @org.gcontracts.annotations.Ensures(value = Rocket$_gc_closure3) public void accelerate() { // 準備:実行前の状態を保持 java.util.Map old = null if ( $GCONTRACTS_ENABLED ) { old = this.$_gc_computeOldVariables() } else { }
13年3月11日月曜日
if ( $GCONTRACTS_ENABLED ) { try { if (org.gcontracts.generation.ContractExecutionTracker.track('Rocket', 'void accelerate()', 'precondition', false)) { java.lang.Boolean $_gc_result = false org.gcontracts.ViolationTracker.init() $_gc_result = new Rocket$_gc_closure2(this, this).doCall() if (!( $_gc_result ) && org.gcontracts.ViolationTracker.violationsOccured()) { try { org.gcontracts.ViolationTracker.rethrowFirst() } finally { org.gcontracts.ViolationTracker.deinit() } } } } finally { org.gcontracts.generation.ContractExecutionTracker.clear('Rocket', 'void accelerate()', 'precondition', false) } } ++( speed )
13年3月11日月曜日
// 事後条件 if ( $GCONTRACTS_ENABLED ) { if (!( old .speed < speed )) { try { assert old .speed < speed : null } catch (org.codehaus.groovy.runtime.powerassert.PowerAssertionError error) { org.gcontracts.PostconditionViolation newError = new org.gcontracts.PostconditionViolation('<org.gcontracts.annotations.Ensures> Rocket.void accelerate() \n\n' + error.getMessage()) newError.setStackTrace(error.getStackTrace()) throw newError } finally { } } } // 不変条件 this.invariant_Rocket() }
13年3月11日月曜日
public boolean isStarted() { java.lang.Object $_gc_result = true this.invariant_Rocket() return $_gc_result }
public int speed() { java.lang.Object $_gc_result = speed this.invariant_Rocket() return $_gc_result }
13年3月11日月曜日
protected java.util.Map $_gc_computeOldVariables() { java.lang.Integer $old$speed = speed java.util.Map old = ['speed': $old$speed ] return old }
13年3月11日月曜日
protected void invariant_Rocket() { if ( $GCONTRACTS_ENABLED ) { try { if (org.gcontracts.generation.ContractExecutionTracker.track('Rocket', 'void invariant_Rocket()', 'invariant', false)) { java.lang.Boolean $_gc_result = false org.gcontracts.ViolationTracker.init() $_gc_result = new Rocket$_gc_closure1(this, this).doCall() if (!( $_gc_result ) && org.gcontracts.ViolationTracker.violationsOccured()) { try { org.gcontracts.ViolationTracker.rethrowFirst() } finally { org.gcontracts.ViolationTracker.deinit() } } } } finally { org.gcontracts.generation.ContractExecutionTracker.clear('Rocket',
13年3月11日月曜日
$GCONTRACTS_ENABLED
•メソッドの呼び出しごとに条件が評価されるのは遅い•$GCONTRACTS_ENABLEDで実行を制御する•-ea,-daVMパラメータで指定
13年3月11日月曜日
3 09, 2013 4:56:21 午後 org.codehaus.groovy.runtime.StackTraceUtils sanitizeWARNING: Sanitizing stacktrace:Assertion failed:
assert 1 == 2 | false
! at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:399)! at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:655)! at A.process(ConsoleScript30:22)
13年3月11日月曜日
Exception thrown3 09, 2013 4:50:36 午後 org.codehaus.groovy.runtime.StackTraceUtils sanitizeWARNING: Sanitizing stacktrace:org.gcontracts.PostconditionViolation: <org.gcontracts.annotations.Ensures> Rocket.void accelerate()
old.speed < speed| | | || 10 | 9| false[speed:10]! at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:399)! at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:655)! at Rocket.accelerate(ConsoleScript29:8)
13年3月11日月曜日
4.まとめAdd-up
13年3月11日月曜日
まとめ•原本を読んでね。•使ってみてね。
13年3月11日月曜日
エヴァンジェリスト活動
13年3月11日月曜日
私大好き
13年3月11日月曜日
13年3月11日月曜日
@bleisさん大好き
13年3月11日月曜日
13年3月11日月曜日
ご清聴ありがとうございました。
13年3月11日月曜日