Higher Order Messaging in Smalltalk – Part 2

Este post é uma continuação da parte 1.

Processando coleções

#select

O processamento de coleções segue uma rotina em alguns casos parecida com o seguinte: para cada elemento da coleção se aplica uma operação que define uma seleção, coleta, busca ou transformação dos elementos.

Um exemplo típico é expressso pelo código:


| salariedEmployees |
salariedEmployees := OrderedCollection new.
employees do: [ :employee | (each hasSalary: 1000) ifTrue: [ salariedEmployees addObject: employee ] ]

Ou então pelo código equivalente mais compacto:

salariedEmployees := employees select: [ :each | each hasSalary: 1000 ]

Embora o código em Smalltalk já seja bem compacto com a introdução de HOM (Higher Order Messaging) algum ítens sintáticos (poucos no Smalltalk) podem ser removidos. Restariam somente os ítens em negrito como abaixo:

salariedEmployees := employees select hasSalary: 1000

Abaixo mostramos o método Employee>>#hasSalary:

Vamos usar o excelente debugger do Smalltalk conjugado com o framework para teste de unidade como exemplos de uso. O teste abaixo, que faremos ser bem sucedido, servirá para uma abordagem top down de refinamento do código:

O execução do teste acima causa erro.

Uma OrderedCollection não responde à mensagem #select. Inicialmente vamos evitar alterar OrderedCollection mas uma subclasse HOMOrderedCollection.

Vamos fazer com que uma HOMOrderedCollection retorne um trampoline (um proxy) que entenda a mensagem #select (Procurando por proxy pattern para criar o link precedente encontrei o paper Efficient Proxies in Smalltalk que talvez seja interessante consultar durante o refactoring que pretendo fazer no final). Para isto não implementaremos um método #select em HOMOrderedCollection mas faremos o override do método #doesNotUnderstand: em HOMOrderedCollection.

HOMTrampoline armazena mensagem e o receptor nas suas variáveis de instância e tem como descendente HOMCollectionTrampoline.

Testando de novo, após adequar a fixture para usar a nova collection, obtemos o erro:

O objeto HOMCollectionTrampoline  interposto como proxy não sabe como responder à mensagem #hasSalary:. Vamos corrigir a situação. Mas não queremos que o proxy responda à mensagem #hasSalary: mas que os elementos da collection que recebeu a mensagem #select respondam à mensagem #hasSalary:. E que o método de agregação seja o #select:, aplicável a uma HOMOrderedCollection. Para isso também vamos fazer o override do método #doesNotUnderstand: em HOMCollectionTrampoline.

O código (message selector , ':') asSymbol transforma o seletor de mensagem #select em #select:, que é aceito por HOMOrderedCollection. O bloco [:each | each perform: aMessage selector withArguments: aMessage arguments] que serve de argumento para a coleção faz com que a mensagem #hasSalary: seja avaliada por cada elemento (Employee) da coleção.

O teste agora passa.

O código está pronto para executar com os iteradores #select:, #collect:, #do: e outros aplicáveis a uma coleção.

Continua na terceira parte.

Anúncios

4 Respostas para “Higher Order Messaging in Smalltalk – Part 2

  1. Pingback: High Order Messaging in Smalltalk – Part 1 | Crab Log

  2. Sei não… mas desse jeito você vai implementar o Haskell em Smalltalk…

  3. Rafael, se for o caso, e não acredito que seja, já o fizeram em Objective C conforme atesta o paper usado como base para este post. Como Higher Order Messaging é inspirado em Higher Order Functions, mas essa não é a única característica das linguagens funcionais, acredito que faltaria muita coisa e que algumas não poderiam ser incorporadas facilmente na biblioteca do Smalltalk (nem sei se seria possível pois não explorei muito as linguagens funcionais).

  4. Pingback: High Order Messaging in Smalltalk – Part 3 | Crab Log

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s