super super & sub sub の話

23
27Smalltalk勉強会 - Smalltalkの超能力 2010 Tetsuya Hayashi 2010 Masashi Umezawa

Upload: masashi-umezawa

Post on 15-Jan-2015

57 views

Category:

Software


2 download

DESCRIPTION

Smalltalkのメソッド探索の仕組みを自在にいじってみるという話

TRANSCRIPT

Page 1: super super & sub sub の話

第27回 Smalltalk勉強会 - Smalltalkの超能力

2010 Tetsuya Hayashi2010 Masashi Umezawa

Page 2: super super & sub sub の話

動機 Smalltalkのsuperpowers紹介なのでsuperに関わる何かをしたい

実際OOPSLA 2008のSmalltalk superpowers では Travis Griggs さんがsuper superの話をした模様

メソッド探索部分をいじる好例であろう

Page 3: super super & sub sub の話

特徴

通常のsuper

メソッド探索を自分のスーパークラスから開始

super superと書くと… メソッド探索を自分のスーパークラスのスーパークラスから開始する

メッセージなので super super super superなどと書くことも可能

=> オブジェクト指向はさらに自由になったw

Page 4: super super & sub sub の話

作り方

Travisさんの実装はVisualWorksで行われていたので、Squeak版を作った

ついでに調子に乗ってメソッド探索を自分のサブクラスから開始するsubも作った

使ったテクニックはほぼ同じ

割と素直な実装

Page 5: super super & sub sub の話

テクニック (1) Object >> doesNotUnderstand: aMessage

理解できないメッセージを受け取ったときにVMから送信されるコールバック

aMessageにはもともと送られたメッセージが入る

Rubyだとmethod_missing

オーバーライドすると、メッセージを自分以外の誰かに受け流すことが可能

Page 6: super super & sub sub の話

例: doesNotUnderstand:でプロキシ

プロキシの実装

MyLogProxy >> doesNotUnderstand: aMessageLogger log: aMessage.^ realObj perform: aMessage selector

withArguments: aMessage arguments

Page 7: super super & sub sub の話

テクニック (2)

CompiledMethod

その名の通り、コンパイルされたメソッド

各クラスの持つmethoDictionaryに値として格納されている

○キーはメッセージセレクタのシンボル

aClass compiledMethodAt: selector で取り出せる

○もしくは aClass >> selector

バイトコードをいじったりもできるが、今回はおとなしく間接的な起動用に使う

Page 8: super super & sub sub の話

例: CompiledMethodによるメソッド起動

通常の場合

ord := OrderedCollection with: 1 with: 2.ord add: 3.

ord := OrderedCollection with: 1 with: 2.method := ord class compiledMethodAt: #add:.method valueWithReceiver: ord arguments: #(3).

CompiledMethod経由では…

Page 9: super super & sub sub の話

テクニック (3)

thisContext

実行中のコンテキストが入っている特殊変数

○ true, false, nil, self, superに次ぐ、第6の予約語

○約束事の少ないSmalltalkでは希有の存在

典型的にはデバッガの実装などで使われる

thisContext sender で送信者のコンテキストが得られる

○次々にたどっていくことも可能

Page 10: super super & sub sub の話

例: thisContextでアクセス制御

privateメソッドの実装※

Object >> privateself class = thisContext sender sender methodClass

ifFalse: [SmallTalkAccessViolation private signal]

methodAself private....

使用例

※ SmallTalk R4.1 - http://smalltalk.smalltalk-users.jp

Page 11: super super & sub sub の話

コードの解説(1)

AnySendというクラスを定義

ProtoObject subclass: #AnySendinstanceVariableNames: 'receiver searchClass'classVariableNames: ''poolDictionaries: ''category: 'SuperSuper'

receiver ->メッセージの受けとり手

searchClass -> メソッド探索の起点となるクラス

Page 12: super super & sub sub の話

コードの解説(2) AnySendはProtoObject(Objectのさらに上)を継承

ほとんど全てのメッセージに答えられないため、doesNotUnderstand: が起動される

CompiledMethodを取り出して起動

doesNotUnderstand: aMessage^((searchClass whichClassIncludesSelector:

aMessage selector) >> aMessage selector)valueWithReceiver: receiverarguments: aMessage arguments

Page 13: super super & sub sub の話

コードの解説(3) Object >> superを用意

AnySendをsuper:かsupersuper:で作る

thisContextで、直前でsuper(変数)を使っているか判断

super| context sendCode |context := thisContext sender.sendCode := context method at: context pc - 2.^(sendCode == 133)

ifTrue: [AnySend supersuper: self]ifFalse: [AnySend super: self]

Page 14: super super & sub sub の話

コードの解説(4)

AnySend class >> self:

self: anObject^self receiver: anObject

searchClass: anObject class

生成用のクラスメソッドを定義

super: anObject^(self self: anObject) super

AnySend class >> super:

Page 15: super super & sub sub の話

コードの解説(5)

supersearchClass := searchClass superclass

supersuper: anObject^(self super: anObject) super

もう少し生成用のクラスメソッドを

AnySend class >> supersuper:

AnySend >> superでsuperclassをずらす

以上。これで動く!!

Page 16: super super & sub sub の話

デモ super superで真ん中のメソッドを飛ばす

Page 17: super super & sub sub の話

調子に乗ってsubも追加(1)AnySend class >> sub:

sub: anObject^(self self: anObject) sub

AnySend >> sub

subsearchClass := searchClass subclass

subclass^self subclassAt: 1

Behavior >> subclass

Page 18: super super & sub sub の話

調子に乗ってsubも追加(2)

Behavior >> subclassAt:

subclassAt: anIndex| subs |subs := self subclasses

ifEmpty: [self error: 'No subclass'].^subs at: anIndex

ifAbsent: [self error:'No subclass at: ', anIndex printString]

Page 19: super super & sub sub の話

サブクラスは1つとは限らない(1)

methodA((self sub @ 2) sub @ 3) doSomething

2番目のサブクラスの3番目のサブクラスのdoSomethingを起動

とか書けるとクール!!

methodB((self sub << ClassA) sub << ClassB) doSomething

この際だし直接指定もやっておこう

Page 20: super super & sub sub の話

サブクラスは1つとは限らない(2)

AnySend class >> sub

@ anInteger(searchClass inheritsFrom: receiver class)

ifFalse: [self error: '@ can be used after sub'].searchClass := searchClass superclass

subclassAt: anInteger

AnySend >> @

Page 21: super super & sub sub の話

サブクラスは1つとは限らない(3)

<< aClass…"@と同じ"

searchClass := searchClass superclasssubclassClassOf: aClass

AnySend >> <<

subclassClassOf: aClass^self subclassAt: (self subclasses indexOf: aClass)

Behavior >> subclassClassOf:

Page 22: super super & sub sub の話

デモ subとsuperを使って無限ループ

Top >> doSomethingLoopyself waitASecond.self doSomething: 'Hello'.self sub sub doSomethingLoopy.

Middle >> doSomethingLoopyself doSomething: '!!!!'.super doSomethingLoopy.

Bottom >> doSomethingLoopyself doSomething: 'World'.super doSomethingLoopy.

Page 23: super super & sub sub の話

まとめ

Smalltalkでは、メソッド探索の仕方などは簡単にいじれる

クラスを一つ導入していくつかのメソッドを追加したのみ

新たな言語もすぐ作れる

まじめな開発ではsuper superとか使っていたらクビです