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 comentários

  1. 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).

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