Higher Order Messaging in Smalltalk – Part 4

Continuação da parte 3.

Processando coleções

#do

Vamos estender o código para que a iteração também percorra o argumento da mensagem. Até agora percorremos a coleção no papel de receptor da mensagem.

No paper Alice é uma gerente (manager) que possui subordinados (reports). Se quisermos adicionar Sally como um novo subordinado à lista de suboedinados de Alice executamos o código alice addReport: sally.

Numa outra situação Sally, também uma gerente, necessita transferir seus subordinados para Alice. O código para isso é o seguinte:


sally reports do: [ :each | alice addReport: each ].

Eliminando-se a sintaxe relativa à iteração e alterando-se a ordem do termos temos em HOM:

alice do addReport: sally reports each

Agora a iteração deve ocorrer na coleção passada como argumento para #addReport: (que normalmente não deveria receber uma coleção como argumento).

Vamos construir um código de teste de maneira similar às anteriores:

O teste ainda não passa:

A classe Manager está inserida na hierarquia abaixo:

Vamos fazer da mesma forma que adotamos com OrderedCollection. Criaremos a classe HOMObject que tornaremos ancestral de Employee, como abaixo:

Podemos agora colocar a intercepção em HOMObject:

Uma nova classe HOMObjectTrampoline passará a receber as mensagens “desconhecidas” enviadas a objetos descendentes de HOMObject:

A idéia no método HOMObjectTrampoline>>#doesNotUnderstand: é aplicar #addReport: a cada elemento da lista passada como argumento.

O HOMObjectTrampoline criado quando a mensagem #do foi enviada ao HOMObject guarda na variável de instância #message esta mensagem. Quando recebe a mensagem #addReport: o método HOMObjectTrampoline>>#doesNotUnderstand transforma o seletor #do em #do: e executa o iterador #do:, aplicável a uma collection, com um bloco onde #addReport: é aplicado a cada elemento da lista passada como argumento.

Executando-se novamente o teste ele ainda não passa:

Para resolver a situação devemos analisar a ordem em que as mensagens são consideradas pelo Smalltalk no runtime. Repetimos abaixo o código HOM para facilitar.

alice do addReport: sally reports each

Primeiro a mensagem #do é enviada ao objeto alice. O objeto alice não reconhece a mensagem mas retorna um HOMObjectTrampoline. A próxima mensagem #addReport: é enviada ao proxy HOMObjectTrampoline, mas só depois que seu argumento for resolvido. O objeto sally recebe a mensagem #reports e devolve uma HOMOrderedCollection. A coleção retornada recebe a mensagem #each que não reconhece e devolve um proxy HOMOrderedCollectionTrampoline que é, então, passado como parâmetro da mensagem #addReport:. Lembrando que a mensagem #addReport: não é reconhecida pelo seu receptor HOMObjectTrampoline. Ela será manipulada no método HOMObjectTrampoline>>#doesNotUnderstand: (Reproduzido abaixo).

doesNotUnderstand: aMessage
	| collection collectionSelector unaryBlock |
	collectionSelector := (message selector , ':') asSymbol.
	collection := aMessage argument.
	unaryBlock := [:each | receiver perform: aMessage selector with: each].
	^ collection perform: collectionSelector with: unaryBlock

A linha 4 do método acima atribui à variável local collection o HOMOrderedCollectionTrampoline criado pelo envio da mensagem #each. O trampoline citado carrega na sua variável de instância receiver os reports de Sally e na sua variável message a mensagem #each.

Corrigimos a situação mudando a linha 4:

doesNotUnderstand: aMessage
	| collection collectionSelector unaryBlock |
	collectionSelector := (message selector , ':') asSymbol.
	collection := aMessage argument receiver. "	unaryBlock := [:each | receiver perform: aMessage selector with: each].
	^ collection perform: collectionSelector with: unaryBlock

E finalmente introduzimos um teste usando #respondsTo: similar ao usado em HOMOrderedCollectionTrampoline:

E agora o código passa no teste.

Para acomodar um tratamento de erro ainda necessitamos de uma pequena modificação em HOMObjectTrampoline>>doesNotUnderstand: (linha 4). Veja abaixo:

doesNotUnderstand: aMessage
	| collection collectionSelector unaryBlock |

	aMessage argument message selector asSymbol = #each ifFalse: [	^ super doesNotUnderstand: aMessage argument message].

	collectionSelector := (message selector , ':') asSymbol.
	collection := aMessage argument receiver.
	(collection respondsTo: collectionSelector)
		ifTrue: [unaryBlock := [:each | receiver perform: aMessage selector with: each].
			^ collection perform: collectionSelector with: unaryBlock].
	^ super doesNotUnderstand: message

Continua na parte 5.

Anúncios

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

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

  2. Pingback: Higher 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