web-dev-qa-db-ja.com

whileTrue:はSmalltalkでどのように機能しますか?

知りたいwhileTrue:機能します。 BlockClosureにある実装を検索しました:

whileTrue: aBlock 
    ^ [self value] whileTrue: [aBlock value]

パラメータのない別の実装:

whileTrue
    ^ [self value] whileTrue: []

しかし、それがどのように機能するかはわかりません。それは再帰的な方法ですが、これによりいくつかの質問をするようになりました:

  1. この再帰呼び出しはどのように終了しますか?
  2. [self value]Booleanオブジェクトを返します。なぜwhileTrue:Booleanタイプに実装されていませんか?
  3. whileTrueという名前の別の実装で、ブロックをまったく受信せず、selfを評価するのはなぜですか?

whileTrue:はコンパイラーによってインライン化されるため、実際の実装は表示されません。これがPharoのコメントです:

「通常はインラインでコンパイルされるため、オーバーライドできません。これは、メッセージがリテラルブロック以外に送信される場合です。レシーバの値がtrueである限り、引数aBlockを評価してください。」

#whileTrue:のバイトコードを見ると、コンパイラがジャンプを使用してループを作成していることがわかります。

17 <70> self
18 <C9> send: value
19 <9C> jumpFalse: 25
20 <10> pushTemp: 0
21 <C9> send: value
22 <87> pop
23 <A3 F8> jumpTo: 17 <---- here's the jump
25 <7B> return: nil

#whileTrueも直接インライン化されます(わずかに最適化されたバイトコード)。インライン化は、これをBooleanに実装しない理由でもあります(ブール値を再評価する意味がないという事実は別として...)。

#whileTrueがあるので、エンドポイントだけを終端するような無限ループを簡単に作成できます。プロセスが終了すると、セマフォが通知され、例外が発生します。

5
Max Leske

私のSmalltalkは少し錆びており、現時点ではSmalltalkをインストールしていないため、ここに構文エラーがあるかもしれませんが、次のように考えます。

whileTrue: aBlock
    ↑ self value ifTrue: [aBlock value. self whileTrue: aBlock]

Rubyのバージョンは次のとおりです。実際にテストしましたが、上記(私が望む))は翻訳です:

class Proc
  def vhile(block)
    self.().iff(thn: -> {block.(); vhile(block)})
  end
end

Smalltalkスタイルの条件文を機能させるには、次のモンキーパッチが必要です。

class TrueClass
  def iff(thn:, els: ->{})
    thn.()
  end
end

class FalseClass
  def iff(thn:, els: ->{})
    els.()
  end
end
3
Jörg W Mittag