Você está na página 1de 18

Estudo das Diferenças entre a Herança por Delegação

e a Herança por Concatenação

Maria José Angélico Gonçalves


mjose@iscap.ipp.pt
Maio de 2007

08T151A011 - Tecnologías de Objetos


Curso de Doutoramento: Engenharia de SW basada en Componentes Reutilizables,
Aplicaciones en Interfaces Hombre-Maquina

1. Introdução

A herança é considerada, geralmente, a característica que distingue a


programação orientada a objectos de outros paradigmas de programação mais recentes.
Embora, este mecanismo tenha sido amplamente estudado pela comunidade científica,
ainda é um tema bastante controverso. Os investigadores tendem a discordar
relativamente ao seu significado e ao seu uso (Taivalsaari, 1996).

“Herança é um mecanismo de modificação incremental na presença de late-


bound self-reference”
Adaptado de Cook (1989) e Cook and Palsberg (1989) citado em Taivalsaari,(1996)

Geralmente late-binding1, self-reference2 e super-reference3 estão presentes em


todos os mecanismos de herança. Late-binding e self-reference permitem que o
programador execute a “cirurgia” que pode mudar o comportamento do objecto sem o
alterar fisicamente. Super-reference adiciona a estas potencialidades a permissão do
acesso às propriedades redefinidas, reduzindo desse modo a necessidade da duplicação
do código. A combinação correcta destas potencialidades permite que as propriedades
dos objectos se reutilizem sem existência de cópia. Esta característica é a principal
vantagem a outros estilos e técnicas de programação (Cook, 1989).

Neste sentido, a herança é um mecanismo fundamental para a construção de


programas. É, frequentemente, referenciada na bibliografia como uma solução de
problemas no desenvolvimento de software. Veio trazer muitos benefícios à
programação, tais como: modelação, simplificação e reutilização.

Neste trabalho referem-se, em primeiro lugar, os aspectos principais das


linguagens de programação orientadas a objectos baseadas em classes (POO baseada em
classes) e das linguagens de programação orientada a objectos baseadas em protótipos
(POO baseada em protótipos).

1 É uma associação feita pelo compilador/interpretador entre um atributo e uma entidade que ocorre durante o tempo de execução
ou muda durante a execução do programa.
2 A designação depende da linguagem de programação. Para o programador, self-reference aparece tipicamente na forma de uma
pseudovariavel especial, self. Pode ser usada explicitamente para informar o sistema que está pedido late-binding via self-
reference.
3 São classes cujas instâncias também são classes. Dependendo da linguagem de programação utilizada existe/não existe suporte
implícito/explicito.

1
Em segundo lugar, é definido o conceito de herança, efectuada uma breve
síntese da sua evolução, e são mencionadas aplicações desse conceito, no contexto da
sua utilização prática. Em seguida, são apresentadas duas formas básicas de
implementação da herança: Delegação e Concatenação. São citadas algumas
linguagens de POO que as aplicam e apresentadas as vantagens e desvantagens da
delegação versus concatenação.

Por último, é efectuado um estudo comparativo de três sistemas de programação


orientados a objectos baseados em protótipos: Self, Kevo e Zero. Nos mesmos, são
exemplificados os conceitos anteriormente apresentados e referidas as principais
diferenças das linguagens.

2. Programação Orientada a Objectos (POO) baseada em Classes versus


POO baseada em Protótipos

Um objectivo importante que as linguagens de programação devem integrar, é a


ortogonalidade, ou seja, a possibilidade de um conjunto relativamente pequeno de
construções primitivas poder ser combinado com um número relativamente pequeno de
maneiras para construir as estruturas de controlo e de dados da linguagem. A falta de
ortogonalidade acarreta excepções às regras da linguagem.

Praticamente todas as linguagens de programação orientadas a objectos são


baseadas em classes (C++, Object Pascal, Java; Eiffel; Common Lisp; CorbaScript;
Perl, etc.) ou baseadas em protótipos (Self; Ómega; Kevo; Poet/Mica, Cecil, JavaScript;
MOO;NewtonScript, etc). A grande maioria baseia-se em classes (Morales, 2000;
Taivalsaari A., 1995). A programação das linguagens baseadas em classes é obtida
através da definição de classes (definição dos atributos e operações dos objectos dessa
classe) e criação de hierarquias, nas quais propriedades comuns são transmitidas das
superclasses para as subclasses através de mecanismos de herança, referida na
bibliografia como class inheritance , standard inheritance ou, simplesmente,
inheritance (Taivalsaari, 1995; Stein , 1989). Objectos destas classes são instanciados
de forma que a execução do programa é vista como um conjunto de objectos
relacionados que se comunicam enviando mensagens uns aos outros.

As linguagens baseadas em protótipos não utilizam a noção formal de classe (ver


figura 1), os objectos copiam-se de outros já existentes (Morales 2003, Borning 1986,
Liberman 1986). A estrutura e comportamento de um conjunto de objectos não se
define através de classes, define-se através de protótipos. O protótipo é, também, um
objecto com uma estrutura, conteúdo e comportamento predefinido, que é utilizado para
criar novos objectos mediante um processo de cópia, denominado cloning. A delegação,
referida na bibliografia prototype inheritance, object inheritance or delegation
(Taivalsaari, 1995) permite a partilha entre objectos e permite que um objecto possa
alterar as suas respostas para pedidos de serviços em tempo de execução.

Um protótipo pode ser pensado como, por exemplo, uma instância, que
representa o comportamento de alguns conceitos. Conforme foi dito anteriormente os
sistemas baseados em protótipos não apresentam classes, pelo que, não existe a noção
de instância (Lieberman, 1986). O efeito de instanciação é a possibilidade de criar
vários objectos com características similares, com a possibilidade de se modificarem
individualmente, utilizando um processo de cópia.

2
Não existe um modelo standard de implementação de sistemas baseados em
protótipos. Anteriormente, foram mencionadas várias linguagens de programação, que
apresentam características muito diferentes. Porém, as mesmas podem ser divididas em
duas categorias: linguagens baseadas em delegação e linguagens baseadas em cópia
(cloning). Nas linguagens baseadas em delegação há um mecanismo especial
“Delegation” que fornece a potencialidade incremental da modificação no
desenvolvimento de software (Lieberman 1986).

Figura 1 – Criação de um objecto com classes e com protótipos


Fonte: Morales (2003), Programación Orientada a Objetos: Clases versus Prototipos

“Delegação (delegation) é um mecanismo geral de partilha entre duas ou mais


estruturas separadas. Este mecanismo requer a presença de late-bound e self refence, e
opera no envio de mensagens de um objecto a outro sem alteração de Self-reference”

(Taivalsaari 1995).

Se um objecto “filho” não implementa uma determinada mensagem ele delega a


mensagem para o objecto “pai”. Caso o objecto pai implemente aquela mensagem então
ele executa-a com os dados do objecto “filho”, senão o objecto “pai” delega a
mensagem nos seus “delegatee´s”. Pode existir uma lista de objectos para os quais as
mensagens são delegadas. Esta situação causa conflito tal como na herança múltipla,
referida em seguida. A solução é a existência de uma lista sequencial de objectos.

Exemplo de sintaxe de uma linguagem por delegação (Taivalsaari,1995):

Var/ Method/Parent slotName [:-SlotContents]

slotName – nome da nova variável


Method, ou parent slot e slot contents (opcional) – o objecto será accionado por
slotName.

3
Ungar, Chambres, Chang Holzle (1991), referiram que a linguagem Self pode
incorporar tarefas realizadas em linguagens baseadas em classes. Esta linguagem
diferencia dois tipos de objectos: Traits4 e prototypes5.

Independentemente do sistema ser baseado em classes ou em protótipos existem


duas formas básicas de implementação da herança: Delegação e Concatenação
(Taivalsaari, 1996).

3. Herança

3.1 Definição do conceito

Herança é um mecanismo que permite a uma linguagem de programação definir


novos objectos a partir de objectos já existentes. Uma nova classe herda propriedades
dos seus pais e pode introduzir novas propriedades que ampliam, modificam ou
eliminam as propriedades herdadas.

No contexto de programação, o conceito de herança foi introduzido pela


linguagem SIMULA, em 1960, com a designação de concatenation (concatenação).
Posteriormente, denominou-se suclassing , derivation (em C++), prefixing (em Simula e
Beta), subtyping, generalization .

Em 1990, Korson and McGregor (citados em Taivalsaari, 1996) caracterizaram a


herança em duas vertentes diferentes: 1ª – Na Fase de desenho do programa de alto
nível, a herança utiliza-se para modelar relacionamentos de
generalização/especialização. 2ª – Na Fase de implementação de baixo nível de
execução, a herança permite definir classes novas com base em classes já existentes.
Investigadores, mais tarde, fazem uma distinção clara entre herança e subtyping.
Herança, também designada implementação da herança, representação da herança ou
subclasses, em sistemas baseados em classes, é um mecanismo de baixo nível que
partilha ambiente e dados.

Por outro lado subtyping, também designado especificação da herança ou


herança de interface, expressa uma especialização conceptual. Este conceito foi aceite
pela comunidade científica mas poucas linguagens de programação o integraram
(POOL-I e Typed Smalltalk).

Em 1991, LaLonde e Pugh (citados em Taivalsaari, 1996), propuseram as


seguintes definições para os três conceitos: — Subclassing (subclasses) é um
mecanismo da execução para compartilhar o código e representação6; —Subtyping é um
relacionamento substituto — Is-a (É-um) é um relacionamento conceptual de
especialização: descreve um tipo do objecto como um tipo especial de outro.

Subclassing(subclasses), subtyping, e specialization(especialização) são


importantes por razões diferentes. Subclasses suportam reutilização para implementar

4 Descrevem o ambiente do objecto. Correspondem às classes num sistema OO baseado em classes (Ungar, Chambres, chang Holzle, 1991)
5 Contém a informação. Correspondem às instâncias num sistema OO baseado em classes(Ungar, Chambres, chang Holzle, 1991)
6 Podemos adicionar um comportamento específico (implementação) às subclasses de uma hirerarquia de
generalização/especialização - Poliformismo

4
bibliotecas de classes. Subtyping suporta reutilização para que o utilizador da biblioteca
da classe possa saber que classes podem ser substituídas por outras classes. A Relação
de Especialização (É-um ), por sua vez, é importante para compreender os
relacionamentos lógicos entre os conceitos; neste sentido, a especialização é importante
para o programador da biblioteca da classe. Brachman identificou vários tipos de
relações É- um. Wegner distinguiu subtyptes (subset subtyping; Isomorphic copy
subtyping; Object-oriented subtyping) de subtyping.

Actualmente, grande parte dos sistemas orientados a objectos suporta herança


múltipla. Ou seja, é possível que uma classe ou um objecto tenha mais que um parent
(pai).

Existem na bibliografia diferentes noções de herança (Cardelli, 1984; Cook,


1989; Wegner e Zdonik, 1988). De uma forma básica, herança pode ser definida como
uma combinação de registos (Cardelli, 1984; Cook, 1989). Herança não é uma
característica independente da linguagem de programação, porque interage com outros
mecanismos da linguagem.

3.2 Aplicações da Herança

Na prática, as linguagens orientadas a objectos utilizadas em aplicações


comerciais raramente contemplam a herança de relacionamentos (specialization). Neste
tipo de aplicações privilegia-se a economia de esforço na codificação, o espaço de
armazenamento e a velocidade da execução (Smaltalk e C ++) .

Conforme foi dito anteriormente, a herança pode ser vista sobre diferentes
aspectos. Usos diferentes focalizam propriedades diferentes, tais como o
comportamento externo dos objectos, estrutura interna do objecto, estrutura da
hierarquia da herança, ou nas propriedades do software.

a) Herança para Implementação

Refere-se a situações em que é usada a herança não porque as abstracções


(Classificação; Generalização; Agregação e Agrupamento) a serem herdadas são ideais
do ponto de vista conceptual, mas porque contem propriedades apropriadas para nova
abstracção ainda em construção. Este tipo privilegia a economia de esforço na
codificação, o espaço de armazenamento e a velocidade da execução. Os investigadores
criticam este modelo. Posteriormente foram adoptados variações na implementação da
herança – Cancelamento; - Optimização, e - Conveniência (Rumbaugh citado em
Taivalsaari, 1996).

A herança simples é um mecanismo existente no paradigma orientado a


objectos que permite a reutilização da estrutura e do comportamento de uma classe ao
definirem-se novas classes. Quando se define uma nova classe apenas algumas
propriedades que diferem das propriedades da classe já existente precisam de ser
declaradas explicitamente. Todas as outras propriedades são automaticamente extraídas
da classe já existente e incluídas na nova classe (Taivalsaari, 1996). A classe que herda
o comportamento é chamada subclasse e a que o definiu chama-se superclasse (A
máquina virtual Zero suporta herança simples (Schofield et al., 2004).

5
Conforme referido anteriormente, grande parte dos sistemas orientados a
objectos permitem herança múltipla (figura 2, figura 3 e figura 4). Ou seja, é a
possibilidade de se definir uma subclasse com mais de uma superclasse.
Conceptualmente, a herança múltipla é necessária para modelar o mundo real. No
entanto, pode levar a problemas de implementação nomeadamente colisões (collisions).

Herança múltipla utiliza-se para combinar abstracções de igual importância. Em


vários casos este tipo de situações podem também ser naturalmente expressas usando
roles (“papeis”).

As colisões ocorrem quando a herança DGA (Grafo Dirigido Acíclico) contem


propriedades sobrepostas (over lapping ). Ou seja, quando o algoritmo de pesquisa
(lookup) é incapaz de decidir qual dos objectos vai ser executado. Na herança simples a
sobreposição (overlapping) é a possibilidade de alterar as características herdadas de um
objecto. Ou seja, ocorre quando um descendente redefine algumas das propriedades
herdadas para se diferenciar do seu pai. As propriedades recentemente redefinidas
sobrepõem naturalmente as herdadas. Chambers et al (1991) apresentaram duas
abordagens para resolver colisões: herança ordenada (ordered inheritance) e herança
desordenada (unordered inheritance). Para resolver este problema particular o Self,
numa edição mais recente, incluiu um especial sender path tiebreak.

Figura 2 –Herança múltipla em linguagens baseadas em Figura 3 –Herança múltipla em linguagens Figura 4 – Herança múltipla em
classes baseadas protótipos por concatenação linguagens baseadas em protótipos por
Fonte : Taivalsaari (1995) delegação
Fonte: Chambers et al. (1991)

Nem todas as linguagens de programação orientada a objectos suportam herança


múltipla.

Herança dinâmica é a possibilidade de mudar o(s) parent(s) dos objectos


dinamicamente em tempo de execução (Chambers et al,1991). Schofield (2007) refere
que, no caso da herança ser implementada por delegação (estratégia básica de
implementação da herança referida no ponto 3.2) abre-se uma nova possibilidade. O
atributo que menciona o pai (parent) do objecto pode ser alterado. Desta forma, um
objecto pode ser “filho” de vários objectos, dependendo do tempo de execução (ver
figura 5). No ponto 3.4.2 é apresentado um exemplo de implementação de herança
dinâmica.

Este mecanismo de herança traz custos em termos de programação . O que antes


era transparente para o programador agora passa a ser declarado de forma explícita. Para
além disso, pode diminuir a performance do sistema e resultarem alguns erros. Para os
evitar, é necessário coordenar os vários tipos para realizar uma série de tarefas
(Chamber et al., 1991, Schofield, 2007).

6
Figura 5- Herança dinâmica
Fonte: , Schofield (2007)

No entanto, também apresenta vantagens. A sua principal vantagem é a


possibilidade dos métodos se poderem escrever segundo o tipo do objecto. Ajuda a
solucionar erros e a tornar a codificação mais simples (Chamber et al.,1991, Schofield,
2007). O ponto 4.3 apresenta um exemplo de utilização de herança dinâmica.

b) Herança para Combinação

Refere-se a situações em que a herança é usada para combinar abstracções


existentes com múltipla herança ou mixin-based inhertance (herança baseada em mixin)
também designada por subclasses abstractas (Bracha e Cook, 1990)

Herança baseada em mixin, foi utilizada na linguagem de programação baseada


em classes CLOS, Mixin é uma subclasse abstracta que pode ser usada para caracterizar
o comportamento de uma variedade de parent classes (classes pai). Define
frequentemente métodos novos que executam algumas acções e chamam métodos
correspondentes do pai (Bracha e Cook, 1990).

Esta utilização de herança aumenta consideravelmente a reutilização de


definição de classe, mas ao mesmo tempo pode diminuir a clareza conceptual do
sistema requerendo que o mesmo mecanismo de classe tenha de ser usado para três
finalidades diferentes duma maneira menos intuitiva.

c) Herança para Inclusão

Muitas linguagens de programação baseadas em classes não fornecem um


mecanismo do módulo separado (por exemplo, Smalltalk), e assim às vezes são
necessárias classes para simular os módulos ou funções das bibliotecas.

d) Outras utilizações da herança

Relação de Generalização – A(s) superclasse(s) é(são) uma generalização da(s)


subclasse(s).

Relação de Especialização – A(s) subclasse(s) é(são) uma especialização da(s)


subclasse(s).

7
Como conclusão pode referir-se que a comunidade científica ainda não chegou a
nenhuma conclusão sobre o uso apropriado da herança. Embora a especialização seja
considerada como a única razão legítima para a usar.

3.3 Maneiras básicas de implementação da herança: Delegação e


Concatenação

Herança é o relacionamento entre objectos que garante que um descendente tem


as mesmas propriedades dos seus pais, podendo ainda serem-lhe adicionadas, alteradas
ou eliminadas propriedades, tornando desta forma o descendente diferenciado dos seus
pais. Isto implica que o registo que representa o descendente deva ter, pelo menos, os
identificadores que os seus pais têm, podendo ainda o descendente introduzir novos
identificadores7 distintos8 ou sobrepostos (overlapping).

Cook (1989) refere que de uma maneira geral a herança pode ser definida como
uma combinação de operações.

R= P ⊕ △R

Em que nas estruturas dos registos P = […] e R =[…]

R - representa um objecto ou uma classe recentemente definida e P representa as propriedades


de um objecto ou de uma classe existente,
△R - representa as novas propriedades adicionadas para diferenciar R de P,
⊕ - representa uma operação para combinar △R com as propriedades de P.

Taivalsaary (1995) refere que na memória do computador existem duas formas


básicas de definir relações ente coisas: References (referências) ou Contiguity
(contiguidade). Baseado neste princípio, existem duas estratégias básicas para
implementar herança: Delegação e Concatenação. Delegação é a forma de herança em
que as relações do descendente são partilhadas com as relação(ões) do(s) pai(s), ou seja,
usando referências. A concatenação, por outro lado, consegue o mesmo efeito, copiando
as relações dos pais na relação do descendente. Neste caso, a relação dos descendente
será contígua (figura 6).

Para ilustrar esta diferença Travalsaari (1995) utiliza o seguinte exemplo:

O sistema tem implementado o seguinte objecto- Parent,

Parent: - [VAR pv1; Var pv2; METHOD pm1]


Variáveis: pv1;pv
Método: pm1

Suponhamos que pretendemos definir outro objecto, designado Child que herda
as propriedades do pai e é-lhe adicionado mais uma variável e mais um método.

7 Identificadores de objectos são usados por objectos para identificar univocamente outros objectos. Adiciona-se um novo
identificador atribuindo ao identificador um nome diferente dos nomes dos identificadores já existentes.
8 A relação classe /subclasse é representada por DGA (Grafo Dirigido Acíclico)

8
Relação do descendente por delegação:

Child: - [PARENT p: - parent; VAR cv1; METHOD cm1 ]

Relação do descendente por concatenação:

Child: - [VAR pv1; VAR pv2; METHOD pm1; VAR cv1; METHOD cm1 ]

Nota: Os valores reais das variáveis e execução dos métodos foram omitidos.

O resultado é igual para ambos os casos. O objecto Child responde às


mensagens que correspondem a identificadores herdados e adiciona a nova variável e o
novo método. No entanto, o modo como a mensagem enviada é executado é diferente.
Na delegação se o objecto não implementa uma determinada mensagem delega
(repassa) a mensagem ao seu pai. Enquanto que, na concatenação, a relação de cada
objecto é auto-introduzida e neste caso não é necessária nenhuma resposta.

Borning (1986) apresentou uma linguagem baseada em protótipos que não tinha
necessariamente de usar delegação. Demonstrou que utilizando a cópia (cloning) e a
possibilidade de adicionar dinamicamente novas propriedades aos objectos, na presença
de vários mecanismos de envio de mensagem late-binding, é possível capturar a
essência da herança. No entanto, esta linguagem apresentou alguns problemas,
nomeadamente na capacidade de memória requerida e na maior dificuldade de cópia e
modificação dos objectos.

Em ambas as formas básicas de herança – Concatenação e Delegação – são


necessários late-bound e self-reference. Caso contrário as operações herdadas não
poderiam referir as características adicionadas.

Figura 6 – Delegação e Concatenação


Fonte: Taivalsaari (1995). Delegation versus or Concatenation or Cloning is Inheritance too

Em sistemas baseados em classes, a delegação e a concatenação processam-se de


forma bastante diferente. A designação concatenação não é um termo muito usado na
bibliografia. No entanto, foram definidos alguns conceitos que derivaram de Textual
concatenation of program bloks (Cook and Plasberg, 1989), tais como: prefixing (Dahl
e at citados Taivalsaari, 1996). Nas versões actuais da linguagem Simula e da sua
descendente Beta as relações das classes e das subclasses são auto-introduzidas e
independentes umas das outras (Madsen et al. citados em Taivalsaari, 1996). Por outro

9
lado, a implementação da herança em smalltalk, linguagem baseada em classes, é
idêntica à herança por delegação implementada em Self, linguagem baseada em
protótipos. Em ambas as linguagens as mensagens não resolvidas são enviadas para
estruturas separadas. Em Smalltalk é usada uma superclasse, e no Self é utilizado um
objecto pai.

A tabela 1 apresenta as principais diferenças entre herança por delegação e


herança por concatenação.

Estratégia de herança Delegação Concatenação


Estratégia de combinação Partilha/Referencias Cópia/Contiguidade
de registos
Dependência de relações Dependente Independente
(life-time sharing9) (creation-time sharing10)
Herança DAG Assegurada Nivelados
Tabela 1- Delegação versus Concatenação
Fonte: Taivalsaari (1996)

Como conclusão podemos referir que tanto a concatenação como a delegação


são mecanismo de herança utilizadas tanto em linguagens baseadas em objectos como
linguagens baseadas em protótipos (ver tabela 2).

Delegação Concatenação
Smalltalk Simula
Sistemas baseados
Ómega Beta
em classes
Self
IO Kevo
Sistemas baseados Máquina virtual Zero Omega
em protótipos (ainda não possui uma linguagem de
programação de alto nível)

Tabela2 – Esquema de herança em diferentes sistemas


Fonte: Taivalsaari (1995); Dekorte S. (?);Schofield (2004,2007); Ungar, , Holzle (1991)

No ponto 4 vão ser abordado 3 sistemas de programação OO, baseados em


protótipos (Self, Kevo, e a maquina virtual Zero).

3.3. Vantagens e Desvantagens Delegação versus Concatenação

As duas estratégias de implementação de herança apresentam vantagens e


desvantagens. A tabela 3. referencia algumas dessas vantagens

9 Life-time sharing refere a partilha física entre pais e filhos


10 Creation-time sharing: a partilha ocorre apenas enquanto o processo receptor está em progresso.

10
Herança Vantagens Desvantagens
- O modelo conceptual é extremamente - É menos flexível que o Self em tempo
simples e fácil de ensinar (1). de execução (1) (3).
- Os objectos são auto-suficientes, ou seja - Não é possível modificar os pais de
para se compreender o ambiente de um um objecto em tempo de execução, (1).
objecto não é necessário compreender e
- Devido à natureza linear dos objectos
hierarquia da estrutura (1).
não pode ser dada prioridade à herança
- Podem ser adicionadas novas variáveis múltipla, como no Self (1).
que se propagam facilmente aos outros
elementos do grupo (1).
Concatenação - A estrutura linear, do objecto auto-
suficiente permite optimizar o envio da
mensagem (1).
- As relações implícitas do objecto
escondem a implementação das decisões
sobre a partilha/duplicação e são, assim,
mais apropriadas para a programação
concorrente e distribuída (1).
- A combinação da relação do objecto não
requer nenhum conceito de partilha (1).
- Espaço eficiente de partilha (2). - Cria dependências da Web tornando
os sistemas frágeis (2) .
- Utilização conveniente da herança
dinâmica. Preserva as mudanças (2) - Não adaptável ao ensino (3).
- Privilegia a herança dinâmica (4) - Difícil de implementar (3).
Delegação
-Integra bem linguagens/ambientes (2)
- Maleabilidade e reusabilidade (4).
- Facilidade de construção dos programas,
manutenção e extensão (4).
Tabela3 – Vantagens e Desvantagens das estratégias de implementação da herança
Fonte: (1) Taivalsaari (1995, 1996); (2) Cardelli (3) Schofield (2004,2007); (4) Chambers, et al. (1991)

4. Linguagens de programação OO baseadas em protótipos

4.1 Self

O Self é a linguagenm de programação orientada a objectos baseada em


protótipos de referência (Taivalsaari, 1996). É similar ao Smalltalk (Smith e Ungar,
1995) na sintaxe e na semântica, mas enquanto o Smalltalk usa o paradigma baseado em
classes, o Self usa protótipos.

Mecanismo

Objectos

Na linguagem Self, os objectos são compreendidos através de slots Um slot tem


um nome e uma referência a um objecto. Os slots de um objecto contêm o seu
comportamento e o seu estado.

11
A interacção com um objecto é feita através da emissão de uma mensagem. O
nome da mensagem, chamado selector, é combinado com o nome do slot. O slot
responde de acordo com o seu tipo. Há dois tipos de slots: method slots, e data slots. O
method slot contem um método (isto é um código executável) (Ungar e Smith, 1987).

Quando uma mensagem é recebida, é devolvido o resultado da execução do


método. Os data slots são slots que contêm qualquer tipo do objecto que não é
executável, bem como variáveis de classe na programação baseada classe. Quando uma
mensagem é recebida por um data slot retorna simplesmente o conteúdo desse objecto.
Os objectos novos são criados copiando os já existentes. Em seguida, para se obter o
comportamento desejado, adicionam-se slots aos objectos novos (Ungar et al., 1991,
Chambers et al. 1991).

Herança

A herança no Self é efectuada fazendo data slots em parent slots. Os parent slots
delegam mensagens nos objectos que são referidos no caso de o selector de uma
mensagem não ser combinado com nenhum slot do objecto. Isto significa que um
método somente tem que ser escrito uma vez. Quando contido num objecto especial,
chamado trait, esse método pode ser usado por qualquer outro objecto (Chambers et al.,
1991).

4.2 Kevo

Kevo é uma pequena linguagem de programação OO baseada em protótipos


desenvolvida por Taivalsaari (1992). É baseada na ideia de que uma linguagem de
programação, baseada em protótipos, não tem obrigatoriamente que suportar delegação,
como o Self. Conforme referido anteriormente, Kevo usa um mecanismo de herança
chamado concatenação (Taivalsaari, 1992, 1995, 1996).

Mecanismo

Objectos

Em Kevo, os objectos são representados como unidades independentes que


contêm todas as propriedades para o efeito desejado. Isto significa que, ao contrário do
Self, os objectos não compartilham métodos ou dados, pelo menos não logicamente.
Para simplificar a programação, a linguagem Kevo suporta objectos similares que são
agrupados juntos. Suporta também modificações do groupwise destes objectos. Isto
significa que, se um programador alterar um objecto altera também as propriedades dos
outros objectos do grupo (Taivalsaari, 1992, 1995,1996).

Herança

Conforme mencionado anteriormente, Kevo não suporta delegação. Os objectos


herdam as propriedades dos pais, através de mecanismo de concatenação. A
concatenação fornece um par de funções de cópia, e diversas funções de modificação.
Deste modo, para criar um novo tipo do objecto, o programador precisa de copiar um
objecto existente, e aplicar-lhe as operações necessárias para a sua modificação. As
operações da concatenação suportam também a modificação do groupwise.

12
Taivalsaari (2005) refere o seguinte exemplo:

O objecto GraphicThing foi criado por clonagem do objecto Clonable

GraphicThing :- Clonable.clone;
GraphicThing ADDS [
VAR x :- 20;
VAR y :- 10;
METHOD draw :- { ... };
]

Os objectos Ball and Bat foram construídos de uma maneira similar clonando o objecto
GraphicThing, e depois foram-lhe adicionadas novas variáveis e operações.

Ball :- GraphicThing.clone;
Ball ADDS [
VAR xStep :- 1;
VAR yStep :- 1;
METHOD bounce :- { ... increment ball location ... self.draw... };
METHOD serve :- { ... initialize ball location ... self.draw ...};
]
Bat :- GraphicThing.clone;
Bat ADDS [
METHOD moveUp :- { ... decrement y-coordinate ... self.draw... };
METHOD moveDown :- { ... increment y-coordinate ... self.draw ...};
]

Na figura 7 vê-se de uma forma gráfica a codificação referida anteriormente.

Figura 7- Herança do protótipo por concatenação


Fonte: Taivalsaari,1992

13
4.3 Máquina Virtual Zero

Zero é uma máquina virtual, pequena e simples (Zero, 2007 e Schofield et al.,
2004), baseada em protótipos, que teve origem em 2003, na Universidade de Vigo e foi
inspirada em “The Design and Evolution of C++”, de Bjarne Stroupstrup, em 1991. Os
objectivos da sua criação foram os seguintes: 1º Dotar os estudantes de um sistema OO
puro, onde seja possível incluir persistência ortogonal baseada em containers; 2º
Proporcionar que as linguagens de programação OO baseadas em protótipos se tornem
adequadas à docência; e 3º Ser um sistema minimalista, ou seja pequeno e simples,
nomeadamente no que se refere à sua performance. (Zero, 2007)

Esta máquina é constituída por um macroassemblador “zm” (permite


programação); um assemblador (permite executar operações básicas directamente
sobre a máquina, tais como: Criação de objectos, enviar mensagens; incluindo controlo
de excepções); Linguagem de programação Prowl (permite programação de alto
nível); Máquina virtual (executa os objectos criados com o assemblador); Livraria
standard interna (Zero, 2007).

Mecanismo

Objectos

Conforme foi referido anteriormente esta máquina virtual é baseada em


protótipos. Contém dois grandes grupos de registos. O primeiro grupo, é composto por
um acumulador (_acc) - que guarda a referência resultante da instrução anterior; Self
em Java (_.this) – que guarda o objecto que está a executar o método e (_.exc) o registo
que guarda as excepções. O segundo grupo guarda os registos gerais que podem ser
utilizados para qualquer propósito (Schofield et al., 2004; Zero, 2007).

Não existe uma divisão especial entre objectos e protótipos. Os protótipos são
objectos definidos em tempo de compilação. Os objectos criam-se através da clonagem
dos primeiros, em tempo de execução. É, ainda, possível, em tempo de compilação
clonar um objecto, eliminar-lhe ou adicionar-lhe atributos e métodos e aplicá-lo como
protótipo. É possível, também, criar um objecto vazio herdado de outro, passando a
mensagem createchild() e adicionar-lhe os métodos e os atributos(variáveis)
necessários (Schofield et al., 2004).

As mensagens e os métodos executam-se utilizando a mesma sintaxe que a


linguagem Java, <nomeObjecto>.<nome.método>. É possível que entre o nome do
objecto e o nome do método existam nomes de atributos, que devolvem a referência
para um novo objecto.

Herança

Simples

A herança suportada é do tipo simples. Todos os objectos derivam do objecto


Object. É o início da hierarquia da herança. Este objecto fornece as operações básicas a
todos os outros objectos.

14
Existe um atributo especial denominado parent que identifica o pai de um
objecto. No exemplo seguinte PruebaPunto herda de Console Application.

! ================================
! Creación de un objeto Punto
! Ejemplo de programación en Zero
! ================================

object Punto
attribute + x = 0
attribute + y = 0

method + mueve(a, b)
isInstanceOf Float, a
jumpOnTrueTo testB
throw EMismatch ! No lo es

:testB
isInstanceOf Float, b ! Es un número ?
jumpOnTrueTo fin
throw EMismatch ! No lo es

:fin
x=a
y=b
return
endMethod

method + toString()
reference toret

toret = "("
toret = toret.concat(x.toString())
toret = toret.concat(", ")
toret = toret.concat(y.toString())
toret = toret.concat(")")
return toret
endMethod
endObject

object PruebaPunto : ConsoleApplication


method + doIt()
reference x = 100
reference y = 100
reference miPunto = Punto.copy("") ! Copiar el objeto

__this.prepare() ! Inicializaciones
miPunto.mueve(x, y) ! mover al punto
System.console.write(miPunto) ! Visualizar el punto
System.console.lf()
return
endMethod
endObject

Fonte: Schofield J. (2007)

Herança Dinâmica

Este sistema suporta, também, herança dinâmica. Como foi referido


anteriormente, existe um atributo parent que, como qualquer outro, podem ser-lhe
alteradas as suas propriedades através do seu próprio objecto. Esta modificação é
conhecida como herança dinâmica.

Em seguida apresenta-se um exemplo de implementação de herança dinâmica. O


objecto muda de pai mediante o cumprimento de uma condição.

15
! Herencia dinámica -- demostración
! Debe ser guardado como "Dinamica.zm"

object MapaVacio : Map


method + lookUp(name)
throw EObjectNotFound
return
endMethod

method + modify(name, obj)


throw EObjectNotFound
return
endMethod

method + add(name,obj)
System.console.write("MapaVacio::add")
System.console.lf()

__this.^add(name, obj)
parent = MapaNoVacio
return
endMethod
endObject

Fonte: Extracto de exercício 4 (Schofield J. ,2007)

O protótipo MapaVacio é utilizado quando o vector está vazio. Passa a ser


parent quando se introduzem elementos nele próprio. A possibilidade de troca do parent
simplifica bastante a implementação dos métodos modify e add

5. Conclusões

A herança é um mecanismo fundamental na construção de programas. Veio


trazer vários benefícios à programação, tais como: modelação, simplificação e
reutilização.

Pode ser vista sobre diferentes aspectos. Usos diferentes focalizam propriedades
diferentes, tais como: o comportamento externo dos objectos, estrutura interna do
objecto, estrutura da hierarquia da herança ou propriedades das linguagens de
programação.

Embora seja um assunto amplamente estudado pela comunidade científica


(Liberman, 1986; Borning, 1986; Cook, 1989; Bracha e Cook, 1990; Ungar et al.,
1987,1991; Taivalsaari, 1992, 1995, 1996; entre outros) ainda não existe um consenso
sobre como a mesma deve ser usada. No entanto, a especialização conceptual foi
considerada como a única razão legítima para usar a herança.

Independentemente do sistema orientado a objectos ser baseado em classes ou


em protótipos existem duas formas básicas de implementação da herança: Delegação e
Concatenação (Taivalsaari, 1996). Ambas as formas permitem responder a mensagens
que correspondem a identificadores herdados que, posteriormente, poderão ser
alterados. No entanto, o modo como a mensagem enviada é executado é diferente. Na
delegação, se o objecto não implementa uma determinada mensagem, delega (repassa) a
mensagem ao seu pai; enquanto que na concatenação a relação de cada objecto é auto-
introduzida e, neste caso, não é necessária nenhuma resposta (Taivalsaari, 1996, ).

Chambers et. al (1991),Stein et al (1988) e (Schofield (2007) referem que, caso a


herança seja implementada por delegação, abre uma nova possibilidade, denominada

16
herança dinâmica - possibilidade de mudar dinamicamente os pais dos objectos em
tempo de execução. Desta forma, um objecto pode ser “filho” de vários objectos,
dependendo do tempo de execução.

Existem vários sistemas de programação OO baseados em protótipos que usam


diferentes mecanismos, como acabamos de ver no ponto anterior. Contudo o conceito
base é o mesmo – herança. Os sistemas baseados em protótipos, que implementam
herança por delegação, são mais flexíveis, partilham o espaço de uma forma mais
eficiente, utilizam herança dinâmica, preservam a mudança, integram bem linguagens e
ambientes, permitem maleabilidade e reusabilidade. Contudo, são sistemas mais frágeis
e a implementação é mais difícil (Taivalsaari (1995, 1996); Cardelli (1988); Schofield
(2004,2007); Ungar (1991); Stein, et al. (1988); Chambers, et al. (1991).

Embora o conceito de herança tenha sido introduzido pela linguagem SIMULA,


em 1960, com a designação de concatenation (Dahl et al, 1972 e Nygaard e Dahl, 1978
citados em Taivalsaari, 1996) ainda é um assunto de interesse da comunidade científica.

6. Bibliografia

BORNING, A.H.(1986). Classes versus prototypes in object-oriented languages. Em


Proceedings of ACM/IEEE Fall Joint Computer Conference, pp.36-40

BRACHA, G. AND COOK, W. 1990. Mixin-based inheritance. Em


OOPSLA/ECOOP’90 Conference Proceedings (Ottawa, Canada, Oct. 21–25). ACM
SIGPLAN Not. 25, 10 (Oct.), 303–311.

CARDELLI L. (1988).A Semantics of Multiple Inheritance, CiteSeer.IST, Information


and Computation 76, 138-164

CHAMBERS, C., UNGAR, D., CHANG, B.-W. AND HO¨ LZLE, U. (1991). Parents
are shared parts of objects: inheritance and encapsulation in Self. Lisp Symbolic
Comput. 4, 3 (Jun.).

COOK W. R. (1989). A Denotational Semantics of Inheritance. PhD thesis, Brown


University PhD Thesis,.

COOK W. R. e PALSBERG J. (1989). A denotational semantics of inheritance and its


correctness. Information and Computation, 114(2):329{350.

DECORTS Steve (?) prototype-based em languages, on rainer blome´s proto page em


http://www.dekorte.com/docs/protos/

LIEBERMAN, H. 1986. Using prototypical objects to implement shared behavior in


object-oriented systems. Em OOPSLA’86 Conference Proceedings (Portland, Oregon,
Sept. 26–Oct. 2). ACM SIGPLAN Not. 21, 11 (Nov.), 214–223.

MORALES P. (2002). Programación Orientada a Objetos: Clases versus Prototipos.


Novática, num 144, pg 69-72.

17
SCHOFIELD G., ROSELLÓ E., DACOSTA J., COTA PEREZ M.. (2004). "
Programación orientada a objetos educativa en una máquina virtual orientada a
objetos ". Em proceedings of the VII Congreso Iberoamericano de Informática
Educativa, Monterrey, México

SCHOFIELD García Perez- (2007). Tansparencias resumen del curso, y ejercicios,


Plataforma Faitic, Universidade de Vigo. Em http://trevinca.ei.uvigo.es/~jgarcia/cdTO/

SCHOFIELD García Perez-, ROSELLÓ E García.,TORRES Martínez, D. PÉREZ


COTA, M.(2004). Programación orientada a objetos educativa en una máquina
virtual orientada a objetos. Em proceedings of the VII Congreso Iberoamericano de
Informática Educativa, Monterrey, México
SMITH e UNGAR (1995). “Programming as an experience, the inspiration for Self”.
European Congress on ObjectOriented Programming, 1995.

STEIN, L. A. (1989). Towards a unified method of sharing in object-oriented


programming. Em Workshop on Inheritance Hierarchies in Knowledge Representation
and Programming (Viareggio, Italy, Feb. 6–8).

STEIN, L. A., LIEBERMAN, H. e UNGAR, D. (1988). A shared view of sharing: the


treaty of Orlando. In Object-Oriented Concepts, Applications and Databases, W. Kim
and F. Lochowsky, Eds. Addison-Wesley, 31–48.

Taivalsaari A.(1992). Kevo - a prototype based object-oriented language based on


concatenation and module operations. University of Victoria, Victoria, B.C, Canada.

TAIVALSAARI Antero (1995). Delegation versus or Concatenation or Cloning is


Inheritance too. OOPS Messenger 6(3): 2049

TAIVALSAARI Antero (1996). On the Notion of Inheritance. In ACM Comput. Surv.


28(3): 438-479

UNGAR, Chambers et al. (1991). “Organizing programs without classes”. Lisp and
Symbolic Computation 4(3), Kluwer Academic Publishers,

UNGAR, D. e SMITH, R. B. (1987). Self: the power of simplicity. In OOPSLA’87


Conference Proceedings (Orlando, Florida, Oct. 4–8). ACM SIGPLAN Not. 22, 12
(Dec.), 227–241.

WEGNER, P. e ZDONIK, S. B. (1988). Inheritance as an incremental modification


mechanism or what Like is and isn’t like. Em ECOOP’88: European Conference on
Object-Oriented Programming (Oslo, Norway, Aug. 15–17). Lecture Notes in
Computer Sci. 276, Springer- Verlag, 55–77.

Zero (2003). Em http://trevinca.ei.uvigo.es/~jgarcia/TO/zero/index.html

18

Você também pode gostar