Как сообщение Small Talk для: do: реализовано за кулисами? - PullRequest
0 голосов
/ 10 сентября 2018
result := String new. 
1 to: 10 do: [:n | result := result, n printString, ’ ’]. 

Все в smalltalk - это объект, и объекты взаимодействуют через сообщения.

Я не мог понять, как вышеприведенный код понимает сообщение: do:

Как можно перебрать блок от 1 до 10? Откуда он знает, что должен повторять блок столько раз?

Может кто-нибудь объяснить, что происходит под капотом?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Рассмотрим метод

m
  1 to: 10 do: [:i | self doSomethingWith: i]

Вот байтовые коды, которые генерирует Pharo

    pushConstant: 1                   ; i := 1
    popIntoTemp: 0                    ;
@2: pushTemp: 0                       ; i <= 10 ?
    pushConstant: 10                  ;
    send #'<='                        ;
    jumpFalse: @1                     ; if false, go to end
    self                              ; self doSomethingWith: i
    pushTemp: 0                       ;
    send #doSomethingWith:            ;
    pop                               ; 
    pushTemp: 0                       ; i := i + 1
    pushConstant: 1                   ;
    send #'+'                         ;
    popIntoTemp: 0                    ;
    jumpTo: @2                        ; loop
@1: returnSelf

Как видите, сообщение #to:do никогда не отправляется, тогда как #'<=' и #+ - (хотя их нет в исходном коде!). Зачем? Из-за того, что Берт сказал в своем ответе: эти сообщения оптимизированы компилятором Smalltalk. В случае Pharo оптимизация происходит в #to:do:. На других диалектах #to:do: реализован в терминах #whileTrue:, который оптимизируется.

Как только вы поймете, как это работает под капотом , вернитесь к этому, как если бы #to:do: было обычным сообщением с получателем 1 и аргументами 10 и блоком [:i | self doSomethingWith: i]. Оптимизация не должна заслонять семантику, которой должен следовать ваш разум.

0 голосов
/ 11 сентября 2018

Все сообщения Smalltalk следуют шаблону <receiver> <message>.. В этом случае получатель 1 (субстанция Number) и сообщение to:do:.

Вы можете просмотреть класс Number и увидеть реализацию to:do: прямо здесь:

to: stop do: aBlock | nextValue | nextValue := self. [nextValue <= stop] whileTrue: [aBlock value: nextValue. nextValue := nextValue + 1]

В вашем примере stop - это 10, а aBlock - это [:n | result := result, n printString, ’ ’]. Так что, действительно, он посылает value: на aBlock несколько раз.

Теперь, в дополнение к этому, многие Smalltalks генерируют специальный байт-код, когда видят сообщение for:to:, но это всего лишь оптимизация.

...