Programação Orientada a Objeto com Grafos

66
Programação Orientada a Objeto com Grafos Ana Paula Lüdtke Ferreira Leila Ribeiro Abstract This text aims to present a universal model of computation based on graphs and graph transformations. It also shows how this formalism can be used to specify and to program object-oriented concurrent systems. Resumo Este texto visa apresentar um modelo universal de computação baseado em grafos e transformações de grafos, e como este modelo pode ser usado para especificar e programar sistemas concorrentes orientados a objetos. 8.1. Introdução Programas de computador são parte integrante da vida moderna, fazendo com que a maior parte das nossas atividades diárias dependam deles para que possam ser realizadas. Aplicações comuns são terminais bancários, sistemas de reservas de passagens, caixas de supermercado, clientes de correio eletrô- nico, processadores de texto, entre muitos outros. Serviços mais sofisticados são também controlados por programas, como sistemas de telecomunicações, controle de semáforos, pilotos automáticos de aeronaves e mesmo sistemas de suporte à vida utilizados em unidades de terapia intensiva em hospitais. Em geral, tais sistemas necessitam controlar uma quantidade de componentes de software que operam de forma simultânea. Para os usuários, é de fundamen- tal importância que aqueles operem de forma absolutamente correta, visto que falhas podem causar perdas tanto financeiras quanto humanas. Por exemplo, um terminal para reservas de passagens aéreas necessita acessar uma base de dados compartilhada para verificar se um assento está disponível ou não; pilotos automáticos devem receber informações de diversas partes da aero- nave, bem como das condições climáticas exteriores, para garantir que a rota seja seguida apropriadamente; equipamentos de suporte à vida devem moni- torar constantemente os sinais vitais do paciente para que, em caso de algum problema, medidas adequadas possam ser tomadas a tempo. Se uma falha durante a execução de um jogo ou de um editor de texto não traz problemas 387

Transcript of Programação Orientada a Objeto com Grafos

Page 1: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Ana Paula Lüdtke FerreiraLeila Ribeiro

Abstract

This text aims to present a universal model of computation based on graphs and graph transformations.

It also shows how this formalism can be used to specify and to program object-oriented concurrent

systems.

Resumo

Este texto visa apresentar um modelo universal de computação baseado em grafos e transformações

de grafos, e como este modelo pode ser usado para especificar e programar sistemas concorrentes

orientados a objetos.

8.1. IntroduçãoProgramas de computador são parte integrante da vida moderna, fazendo

com que a maior parte das nossas atividades diárias dependam deles para quepossam ser realizadas. Aplicações comuns são terminais bancários, sistemasde reservas de passagens, caixas de supermercado, clientes de correio eletrô-nico, processadores de texto, entre muitos outros. Serviços mais sofisticadossão também controlados por programas, como sistemas de telecomunicações,controle de semáforos, pilotos automáticos de aeronaves e mesmo sistemasde suporte à vida utilizados em unidades de terapia intensiva em hospitais. Emgeral, tais sistemas necessitam controlar uma quantidade de componentes desoftware que operam de forma simultânea. Para os usuários, é de fundamen-tal importância que aqueles operem de forma absolutamente correta, visto quefalhas podem causar perdas tanto financeiras quanto humanas. Por exemplo,um terminal para reservas de passagens aéreas necessita acessar uma basede dados compartilhada para verificar se um assento está disponível ou não;pilotos automáticos devem receber informações de diversas partes da aero-nave, bem como das condições climáticas exteriores, para garantir que a rotaseja seguida apropriadamente; equipamentos de suporte à vida devem moni-torar constantemente os sinais vitais do paciente para que, em caso de algumproblema, medidas adequadas possam ser tomadas a tempo. Se uma falhadurante a execução de um jogo ou de um editor de texto não traz problemas

387

Page 2: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

significativos, falhas na execução de programas considerados críticos podemter conseqüências muito sérias ou mesmo fatais. Mesmo com todas essas pre-ocupações com respeito à necessidade de correção dos programas, existemcasos reportados em que falhas em dispositivos de software ou hardware cau-saram de fato tais perdas. Um exemplo concreto e relativamente recente foi aexplosão do foguete Ariane 5 menos de quarenta segundos após seu lança-mento. A investigação do acidente concluiu que havia um erro no programa decálculo da trajetória do foguete. O mesmo erro ocorreu no computador secun-dário, e o foguete acabou sendo destruído [Huth and Ryan 2000].

Novas técnicas para o desenvolvimento de software surgiram nos últimosanos para atender às necessidades correntes de produção destes artefatos,mas os paradigmas nos quais estas técnicas são baseadas — em especialorientação a objeto, eventos e concorrência — apesar de fazerem com que oprocesso de desenvolvimento em si seja facilitado, o teste e validação destessistemas tornaram-se muito mais complexos e, conseqüentemente, mais sujei-tos a erros. O cenário atual requer técnicas e metodologias que suportem asnecessidades do projeto e desenvolvimento de software moderno. Estas técni-cas devem garantir que o produto final seja consistente e completo em relaçãoà sua especificação.

Apesar da crescente evidência de que métodos formais oferecem benefí-cios em termos da qualidade do produto final, esforços para a introdução des-tes métodos no processo de desenvolvimento inexistem na maior parte dasorganizações. A utilização de métodos formais na indústria freqüentementeesbarra na percepção que estes métodos são difíceis de entender e utilizar[Araújo Jr. and Sawyer 1998]. Adicionalmente, os clientes devem participar noprocesso de especificação, para garantir que as especificações produzidasatendem às suas necessidades. Portanto, um dos desafios mais importantesé criar métodos formais que possam ser entendidos por todos os participantesdo processo de desenvolvimento de software. Acreditamos que gramáticas degrafos podem auxiliar na procura de uma solução para este desafio.

Muitos dos métodos de especificação usados na prática são baseados emalgum tipo de diagrama, que são mais fáceis de entender, mesmo por nãoespecialistas na área de Computação. Visualmente simples, diagramas sãogeralmente construídos a partir de regras sintáticas bem definidas. Se essasintaxe também for equipada com uma semântica formal, tem-se uma lingua-gem visual de especificação que pode ser integrada mais facilmente no pro-cesso de desenvolvimento. Diagramas usados em processos de especificaçãopodem ser modelados por grafos.

Grafos são estruturas algébricas capazes de transmitir uma quantidade sig-nificativa de informação de uma maneira compacta, visual e clara. Relaçõesde qualquer ordem podem ser expressas na forma de grafos. A especificaçãode sistemas computacionais com grafos oferece duas vantagens que são, emgeral, mutuamente exclusivas: (i) sendo estruturas matemáticas, grafos apre-sentam uma semântica bem definida e (ii) contando com uma apresentação

388

Page 3: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

diagramática, especificações baseadas em grafos podem ser mais facilmenteentendidas e produzidas por não especialistas na área de Computação. Assim,técnicas de especificação baseadas em grafos formam uma base sólida para aintegração de métodos formais de especificação e verificação de sistemas noprocesso de desenvolvimento de software [Baresi and Pezzè 2000].

Sistemas baseados em regras descrevem computações por meio de trans-formações locais. Transformações aritméticas, sintáticas e regras de inferên-cia são exemplos familiares. A maior vantagem dos sistemas baseados emregras reside no fato de que a maior parte do conhecimento algorítmico queas pessoas trazem do ensino elementar e médio é baseado em regras: nósconhecemos regras para transformar expressões matemáticas em outras equi-valentes, para calcular o valor de um elemento pertencente a uma equação,para extrair a raiz quadrada de um número positivo, para achar o mínimo deuma função, e assim sucessivamente. Mas este conhecimento algorítmicobaseado em regras não é restrito à Matemática. Desde muito cedo na vida,aprendemos a amarrar nossos sapatos, a trocar um pneu de bicicleta, a fritarum ovo, a nos comportarmos adequadamente à mesa e mesmo algumas tá-ticas para conseguir um namorado(a). Todo este conhecimento nós tambémpassamos adiante, e em geral o fazemos na forma de regras. Em Compu-tação, áreas como definição de linguagens [Hopcroft et al. 2001], programa-ção lógica e funcional [Clark and Taernlund 1982], [Sterling and Shapiro 1994],[Reade 1995], especificação algébrica [Bergstra et al. 1989], reescrita determos [Gadducci 1996], [Kennaway 1995], prova automática de teoremas[Fitting 1996], processos concorrentes [Milner 1989] e sistemas especialistas[Nikolopoulos 1997], [Russell and Norving 1995], [Kosko 1992] foram grande-mente beneficiadas pela utilização de regras.

Transformações de grafos por meio de regras é uma maneira naturalde combinar grafos, para a descrição de estruturas complexas, com re-gras, para a manipulação destas estruturas. Sistemas de transformação(ou reescrita) de grafos combinam as vantagens de grafos e regras em umúnico paradigma computacional [Ehrig et al. 1996b]. A teoria de sistemas detransformações de grafos estuda uma variedade de formalismos que expan-dem a teoria das linguagens formais [Hopcroft 1969], [Hopcroft et al. 2001],[Lewis and Papadimitriou 1998], [Martin 1996] para abarcar estruturas mais ge-néricas especificadas como grafos. Todas as construções existentes na teoriade linguagens também existem na abordagem baseada em grafos: regras, deri-vações e linguagens geradas podem ser definidas para grafos da mesma formaque são definidas para seqüências de símbolos (strings). Uma gramática degrafos consiste de um grafo inicial e um conjunto de regras que transformamgrafos.

Normalmente, o objetivo de construir uma gramática definida sobre seqüên-cias de símbolos é produzir uma linguagem, a linguagem gerada pela aplica-ção das regras da gramática a uma string inicial. Apesar de podermos fazero mesmo com grafos — gerar linguagens onde as frases são grafos — existe

389

Page 4: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

uma interpretação mais interessante para as gramáticas de grafos: o grafoinicial representa o estado inicial de um sistema, e as regras modelam os pos-síveis comportamentos deste sistema. Assim, uma gramática de grafos podeser vista como uma descrição formal ou modelo de um sistema. Neste caso,os grafos gerados pela gramática correspondem aos estados alcançados, e asderivações correspondem às computações do sistema. Como os grafos sãoestruturas que representam de maneira natural a distribuição de um estado, eas regras atuam localmente (cada uma em uma porção do grafo), gramáticasde grafos podem ser usadas para modelar sistemas distribuídos e concorren-tes.

Para definir uma gramática de grafos, precisa-se (i) escolher o tipo de grafoadequado para representar os estados do sistema a ser modelado; (ii) definircomo podem ser as relações entre esses grafos, que darão origem às regras;(iii) definir como se dá a aplicação de uma regra a um grafo. Neste trabalho,apresenta-se a construção dessas definições de modo que a gramática geradaseja adequada para especificar sistemas que seguem o paradigma da orienta-ção a objeto.

Os princípios que regem o paradigma da orientação a objeto – encapsula-mento de dados e código na mesma unidade sintática, oclusão da informação,herança e polimorfismo – mostram-se adequados às necessidades de desen-volvimento modular e distribuído, e de reutilização de código enfrentados porprojetistas e engenheiros de software, sendo talvez hoje o paradigma de de-senvolvimento mais usado, tanto na indústria quanto na academia.

A herança é um mecanismo central na programação orientada a obje-tos, que suporta o projeto incremental de classes (na abordagem baseadaem classes [Cook 1990]) ou objetos (na abordagem baseada em objetos[Ungar et al. 1991]). O mecanismo de herança permite que novas classes pos-sam ser descritas usando a funcionalidade de classes já existentes. Este pro-cesso gera uma hierarquia de classes onde uma classe derivada (herdeira ousubclasse) é uma versão refinada de sua classe primitiva (ancestral ou su-perclasse) ou primitivas, dependendo se herança simples ou herança múltiplaestá sendo utilizada. Uma classe derivada herda todos os dados e operaçõesde suas classes primitivas, e pode adicionar novos dados e operações, bemcomo modificar operações que já estejam definidas. A extensibilidade de clas-ses neste paradigma suporta os requisitos de desenvolvimento incremental ereutilização de código existentes para o desenvolvimento de grandes sistemasde software [Breu 1991].

Juntamente com a herança, outro mecanismo fundamental da orientaçãoa objeto é o polimorfismo. O polimorfismo pode ser descrito como a caracte-rística que permite que diferentes significados possam ser associados a algoem diferentes contextos. Existem várias formas de polimorfismo em linguagensde programação, e a que estamos usando aqui é o chamado polimorfismo desubclasse [Cardelli and Wegner 1985]: um objeto pode pertencer a várias clas-ses distintas, simultaneamente. O polimorfismo de subclasse significa que uma

390

Page 5: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

instância de uma subclasse pode ser usada em lugares onde uma instância dasuperclasse seria esperada. Este conceito de polimorfismo pode ser exempli-ficado pela seguinte situação: se duas classes c1 e c2 estão relacionadas viaherança, com c2 sendo uma subclasse de c1, então em qualquer ponto ondeum objeto da classe c1 é esperado um objeto da classe c2 pode ser usado, jáobjetos da classe c2 são também objetos da classe c1, pois herdam todas ascaracterísticas de c1.

Polimorfismo de subclasse é especialmente interessante em abordagensorientadas a objeto que permitem que métodos sejam sobrescritos (ou rede-finidos). A sobrescrita de um método herdado no âmbito de uma classe de-rivada permite que este método possa ter uma implementação diferente dométodo herdado, embora ambos ainda possuam a mesma assinatura. Nes-sas abordagens, pode ser implementada a chamada ligação dinâmica, que éo mecanismo que seleciona o método a ser executado baseado no tipo do ob-jeto que executará de fato o método. Como uma referência a um objeto deuma determinada classe pode conter objetos de classes diferentes — nome-adamente, de todas as subclasses da classe da referência — pode-se definirum código genérico que é especializado em tempo de execução pela ligaçãodinâmica de métodos redefinidos. Desta forma, o código a ser executado paraefetuar uma dada operação é determinado em tempo de execução, depen-dendo do objeto que executará este código. Isto dá uma grande flexibilidadeao sistema, pois uma mesma solicitação de execução de método pode ter vá-rias implementações diferentes, dependendo do tipo do objeto que recebe estasolicitação. A maioria das linguagens orientadas a objetos suporta a seleção dométodo apropriado a ser executado baseada na classe do objeto que recebea requisição de executar o método [Campione et al. 2000], [Stroustup 2000],[Thomas and Weedon 1997].

Existe na literatura um grande número de métodos formais[Fitzgerald et al. 2005], [CSK CORPORATION 2005], [Smith 1992],[Smith 1999], [Goguen and Malcom 1996] e semi-formais [Booch et al. 1999]para a especificação de sistemas orientados a objetos. Programas orientadosa objetos normalmente usam herança (que é a maneira mais comum de reusode código) e redefinição de métodos para atingir seus objetivos. Portanto,seria esperado que os formalismos para especificação de sistemas orientadosa objeto oferecessem construções correspondentes que refletissem essesconceitos, caso contrário, o formalismo iria negligenciar conceitos que têmuma grande influência na abordagem sendo descrita.

Métodos para modelagem e programação de sistemas orientados a objetosdeveriam apresentar uma série de características, entre as quais: (i) a existên-cia de uma linguagem de especificação formal que possa ser facilmente enten-dida tanto por desenvolvedores de software quanto por usuários finais; (ii) pos-sibilidade de especificar aspectos estáticos e dinâmicos do sistema de formaintegrada, ou seja, no mesmo formalismo; (iii) a existência de uma semânticaformal que seja compatível com operadores de composição, para permitir o

391

Page 6: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

desenvolvimento modular de sistemas; (iv) a possibilidade de especificaçõesmais abstratas serem refinadas em especificações mais concretas, ou mesmoem programas.

Uma maneira natural de modelar sistemas orientados a objetos usandografos é representar objetos e classes como vértices, e atributos e mensagenscomo arcos. A Seção 8.3 mostra que pode-se definir grafos onde as classesestão relacionadas por uma relação de ordem que representa a hierarquia deherança. A relação de redefinição de mensagens (sobrescrita) determina arelação de ordem entre métodos em uma hierarquia de classes. Represen-tar objetos, atributos e métodos desta forma cria uma situação onde os grafosnão mais são definidos por conjuntos e funções, mas por conjuntos parcial-mente ordenados e funções monotônicas, que preservam a relação de ordemsubjacente aos conjuntos. Este trabalho mostra como uma abordagem paraespecificação de sistemas orientados a objetos usando grafos pode ser cons-truída baseada nessas idéias, apresentando também exemplos de uso dessaabordagem.

O restante deste texto está estruturado da seguinte forma: as Seções 8.3e 8.4 apresentam, respectivamente, os conceitos formais de grafos orientadosa objeto e de gramáticas de grafos orientados a objeto, juntamente com exem-plos que ilustram o significado e a utilização destas estruturas. Na Seção 8.5são apresentados exemplos de especificações de sistemas orientados a ob-jeto usando o formalismo apresentado na Seção 8.4. Esta parte do texto visamostrar que, embora a teoria por trás do formalismo seja matematicamente só-lida, sua utilização é simples mesmo por pessoas que não têm formação emprogramação (imperativa ou orientada a objeto) ou especificação formal. Asdefinições dos termos referentes à teoria dos conjuntos e de relações de or-dem usadas nas definições formais das Seções 8.3 e 8.4 são apresentadasformalmente na Seção 8.2. Se o interesse do leitor for meramente a utilizaçãodo formalismo, estes conceitos podem ser ignorados em uma primeira leituradeste material; contudo, se o leitor tem interesse em trabalhar e entender con-ceitos mais aprofundados sobre este método de especificação, o material destaseção é de maior valia.

8.2. Fundamentos matemáticosSendo um método formal de especificação, é natural que os conceitos de

gramáticas de grafos orientados a objeto sejam explicados em termos de cons-truções matemáticas. Esse fato, contudo, não deve assustar o leitor. Mate-mática, no âmbito da Ciência da Computação, além de permitir demonstra-ções de propriedades e soluções de problemas, é também uma linguagem, ecomo tal serve para expressar conceitos de forma clara e sem ambigüidade.Como toda linguagem, também, inicialmente pode se mostrar difícil de enten-der, mas à medida que vamos adquirindo fluência, conseguimos ver suas van-tagens de maneira mais clara. Assim, apesar de ser possível entender umaespecificação escrita neste formalismo sem conhecer em detalhe toda a teoria

392

Page 7: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

envolvida, é interessante conhecer também as definições matemáticas que asustentam. Qualquer desenvolvimento, teórico ou aplicado, sobre essa teoriadepende disso.

Nesta seção são apresentados os fundamentos matemáticos sobre osquais a teoria de gramática de grafos orientados a objeto se sustenta. A leituradesta seção é opcional para quem já possui os conhecimentos básicos de te-oria dos conjuntos, funções, relações e teoria de ordem. Todas as definiçõesestão numeradas e são referenciadas no texto, sendo assim, quando houverqualquer dúvida o leitor pode facilmente consultar a definição pertinente aoentendimento do texto.

8.2.1. Conjuntos, funções e relaçõesA teoria de conjuntos é vista desde o ensino fundamental, embora muitas

vezes suas construções não sejam descritas de maneira precisa. Um con-junto, matematicamente falando, é simplesmente uma coleção (finita ou infi-nita) de elementos. Um conjunto pode ser representado como uma enumera-ção de seus elementos, entre chaves. Por exemplo, {a,b,c}, {gato, cachorro,papagaio} e {0,1,01,10,11,001,010, . . .} são representações válidas de conjun-tos. As reticências no final de um conjunto indicam um conjunto infinito mascujos elementos obedecem a um certo padrão: o conjuntos dos números na-turais, N, por exemplo, pode ser representado como {1,2,3,4, . . .}. Quandoum conjunto é infinito, mas quando o padrão dos elementos não é óbvio as-sim, pode-se representar o conjunto por propriedades de seus elementos. Porexemplo, um número par tem a propriedade de ser divisível por 2, onde o restoda divisão é zero. Desta forma, podemos representar o conjunto dos númerospares por

Pares = {x∈ N | x mod 2 = 0}onde símbolo | é lido como ’tal que’. Ou seja, o conjunto dos números parescontém todos os elementos x (que pertencem ao conjunto N e portanto sãonúmeros naturais) tal que o resultado da divisão inteira desse número x por2 tem resto igual a zero. Ao longo deste texto serão apresentados diversosconjuntos definidos por propriedades. A operação mais importante, do ponto devista do restante deste texto, sobre conjuntos é o produto cartesiano, conformedefinido a seguir.

Definição 8.2.1 (Produto cartesiano) Sejam A e B dois conjuntos. O produtocartesiano de A com B é definido como o conjunto A×B = {(a,b) | a∈ A,b∈ B}.

Definição 8.2.2 (Produto cartesiano generalizado) Sejam A1,A2, . . . ,An, n >1, conjuntos. O produto cartesiano generalizado destes conjuntos é definidocomo o conjunto A1×A2× . . .×An = {(a1,a2, . . . ,an) | ai ∈ Ai , i = 1, . . . ,n}.

Exemplo 8.2.1 (Produto cartesiano) A operação de produto cartesiano so-bre conjuntos aparece com freqüência em muitas aplicações utilizadas na Ci-ência da Computação. A seguir mostramos alguns exemplos:

393

Page 8: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

• dados dois conjuntos A = {a,b,c} e B = {1,2}, o produto cartesiano de Acom B é dado pelo conjunto A×B= {(a,1),(a,2),(b,1),(b,2),(c,1),(c,2)};

• em geometria analítica, usamos o termo R2 para indicar o plano car-tesiano; R2, no entanto, significa R×R, ou seja, o produto cartesi-ano do conjunto dos números reais, R, com ele próprio. Por definição,R2 = R×R = {(x,y) | x∈R,y∈R}, ou seja, o plano cartesiano é na reali-dade o conjunto de todos os pontos (x,y) que perfazem este plano;

• se quisermos trabalhar com representação de elementos no espaço, pre-cisamos de uma coordenada adicional, então o conjunto R3 é o produtocartesiano generalizado R×R×R = {(x,y,z) | x∈ R,y∈ R,z∈ R};

• quando se define uma estrutura de dados de tipo registro (record , emPascal, struct em C), estamos de fato definindo um produto cartesiano.Imagine que temos o seguinte código (em Pascal):

type data = recorddia: integer;mes: integer;ano: integer;feriado: boolean;

end;

então data é o conjunto formado pelos elementos {(dia, mes, ano,feriado) | dia, mes, ano ∈ Z, feriado ∈ {true, false}}, ou seja, data =Z×Z×Z×{true, false}.

As noções mais importantes das quais necessitamos para entender o res-tante deste texto são as de relação e função.

Definição 8.2.3 (Relação) Sejam A1,A2, . . . ,An conjuntos. Uma relação n-áriaR sobre os conjuntos A1,A2, . . . ,An é qualquer subconjunto do produto cartesi-ano A1×A2× . . .×An.

Matematicamente, uma relação é um subconjunto de um produto carte-siano. Para relembrarmos, um produto cartesiano é um construtor de tuplasordenadas, onde cada um dos elementos pertence a um dos conjuntos ope-randos. Podemos relacionar diversas coisas ou pessoas. Por exemplo, todaconta bancária tem um titular, todas as pessoas têm uma data de nascimento,todas as casas têm um endereço, e assim sucessivamente. o Exemplo 8.2.2apresenta mais exemplos de relações, sob o ponto de vista de sua definição.

Exemplo 8.2.2 (Relação) Vejamos então, como podemos expressar uma re-lação matematicamente: imagine que queremos relacionar todas as pessoascom seu respectivos pais, por meio de uma relação que vamos chamar de R.Um pai ou mãe de alguém também é uma pessoa, então podemos construirtodas as triplas ordenadas ( f , p,m), onde cada um desses elementos pertence

394

Page 9: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

ao conjunto P das pessoas. No entanto, esta tripla só vai pertencer à relação Rse o elemento f tiver como pai o elemento p e como mãe o elemento m. Sendoassim, se construirmos todas as combinações possíveis (x,y,z) ∈ P×P×P, arelação R (que contém as triplas onde o primeiro elemento é filho do segundocom o terceiro, então claramente R⊆ P.

Outro exemplo, agora retirado do âmbito da Ciência da Computação: aspossibilidades de valores em uma linha de uma tabela de um banco de da-dos podem ser vistas como um produto cartesiano dos tipos dos elementosrelacionados. Por exemplo, uma tabela que mantém dados sobre funcionáriosde uma empresa, como por exemplo nome, cargo, salário e tempo de serviço,pode ser vista como um subconjunto do produto cartesiano Nome× Cargo ×R×N, onde Nomeé um conjunto de nomes de pessoas, Cargo é o conjuntodos cargos que a empresa tem, R é o conjunto dos números reais e N é o con-junto dos números naturais. A tabela, contudo, não terá todas as possibilidadede tuplas desse conjunto (até porque esse número é infinito), mas terá exa-tamente o número de linhas que o número de funcionários da empresa, comseus respectivos nomes, cargos, salários e tempos de serviço. Esses dadossão claramente um subconjunto de todos os dados possíveis, o que caracterizamatematicamente uma relação.

Algumas relações têm propriedades especiais, e as relevantes para estetexto são listadas a seguir:

Definição 8.2.4 (Relações binárias) Uma relação R é dita binária se for umarelação 2-ária. Uma relação binária R⊆ A×A é dita

• reflexiva , se sempre que a∈ A então (a,a) ∈ R.

• simétrica se sempre que (a,b) ∈ R então (b,a) ∈ R.

• antisimétrica se sempre que (a,b) ∈ R e (b,a) ∈ R então a = b.

• transitiva , se sempre que (a,b) ∈ R e (b,c) ∈ R então (a,c) ∈ R.

Exemplo 8.2.3 (Relações binárias) Um exemplo de relação reflexiva é a re-lação de igualdade = sobre os reais: para todo número real r ∈ R temos quer = r. Um exemplo de relação simétrica é a relação “ser casado com”: paraquaisquer duas pessoas x e y, se x é casado com y, então y é casado com x.Um exemplo de relação antisimétrica é a relação de comparação entre reais 6:se x 6 y e y 6 x, então naturalmente temos que x = y. Um exemplo de relaçãotransitiva é a relação binária “ser antepassado de”, sobre o conjunto das pes-soas: se x é antepassado de y e se y é antepassado de z, então x também éantepassado de z.

Definição 8.2.5 (Função) Uma função n-ária f é uma relação (n + 1)-áriaR ⊆ A1 × A2 × . . .× An × B, tal que para quaisquer tuplas (a1,a2, . . . ,an,b) e(a1,a2, . . . ,an,b′) ∈ R, onde a1 ∈ A1, a2 ∈ A2, . . . ,an ∈ An e b,b′ ∈ B, tem-se queb = b′. Neste caso escreve-se f : A1×A2× . . .×An → B, onde A1×A2× . . .×An

é chamado de domínio e B é chamado de contradomínio da função.

395

Page 10: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Esta definição de função pode parecer muito diferente daquilo que aprende-se na escola a chamar de função, mas de fato é somente sua caracterizaçãoformal. Usualmente, uma função matemática é representada pela sua lei deformação, por exemplo, f (x) = x2. Essa forma de representação contém infor-mação sobre a função, mas esta informação não é completa. Para descreveruma função também é fundamental informar o seu domínio de definição (quaissão os elementos aos quais a função deverá ser aplicada) e o seu contradomí-nio (em que conjunto estão as imagens dos elementos resultantes da aplicaçãoda função). Naturalmente que o domínio e a lei de formação da função definemo seu contradomínio. No caso da função f , seu domínio pode ser o conjuntodos números naturais, dos inteiros, dos reais, dos complexos ou qualquer sub-conjunto finito ou infinito destes, embora usualmente as funções matemáticastenham como domínio implícito o conjunto R, a não ser que algo seja dito emcontrário. Uma função, contudo, não precisa ter somente um argumento. Afunção que, dado um ponto (x,y)1 no plano retorna a distância deste ponto atéa origem (0,0) é dada por d(x,y) =

√x2 +y2. A função d : R×R → R neste

caso, recebe como argumentos dois valores reais x e y (ou um par ordenadode valores reais (x,y)) e retorna o valor real correspondente a

√x2 +y2. Assim,

pode-se representar a função d : R×R→R como uma relação contida no con-junto R×R×R, definida como d = {(x,y,

√x2 +y2) | x,y ∈ R}, e naturalmente

que d ⊆ R×R×R. Ou seja, toda função que recebe n argumentos pode serrepresentada por uma relação n+1-ária (uma relação em que suas tuplas têmn+1 elementos) onde os primeiros n elementos são os argumentos da função eo último elemento é o resultado da aplicação da função aos seus n argumentos.Assim, a função f (x) = x2 pode ser igualmente representada por uma relaçãoque contém os pares ordenados (1,1),(−1,1),(3,9),(−5,25) e assim sucessi-vamente (para todos os valores possíveis). Formalmente, a relação f pode serdefinida como f = {(x,x2) | x∈ R}.

As relações d = {(x,y,√

x2 +y2) | x,y ∈ R} e f = {(x,x2) | x ∈ R} definidasacima são funções porque a lei de formação assegura que para quaisquer ar-gumentos das funções, seu resultado, isto é, o último elemento da tupla, éúnico. Existe somente uma distância de um ponto à origem, e existe somenteum quadrado de um número.

Definição 8.2.6 (Função total, função parcial) Sejam D e C dois conjuntos.Uma função f : D →C é dita total se, para todo elemento x∈ D existe um ele-mento f (x) ∈C. Uma função é dita parcial se existe pelo menos um elementox∈ D que não é mapeado por f .

Toda função parcial f : D →C pode ser fatorizada em duas funções totais,f ? : dom( f ) → D e f ! : dom( f ) → C, onde dom( f ) ⊆ D contém exatamente oselementos mapeados por f , f ? é a função de inclusão desse subconjunto em

1 Note que este é um par ordenado pertencente ao conjunto resultante do produto carte-siano R2 = R×R.

396

Page 11: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

D ( f ?(x) = x, para qualquer x∈ dom( f )) e f ! é a função f restrita aos elementosde seu domínio ( f !(x) = f (x), para qualquer x∈ dom( f )). Quando uma funçãoé a restrição de outra a algum subconjunto de seu domínio usa-se o operador| para denotar este fato. No caso anterior, escreve-se que f ! = f |dom( f ).

Dadas duas funções f : A→ B e g : B→ C, define-se a composição de fcom g, denotada por g◦ f : A→C a função que a cada elemento do domíniox∈ A faz corresponder o elemento g( f (x)) ∈C.

Usualmente, em matemática, trabalha-se com funções totais. Em Compu-tação, no entanto, funções parciais aparecem em várias situações. Um pro-grama, por exemplo, pode ser matematicamente descrito como uma função,que mapeia entradas em saídas. A própria noção de “função” nas linguagensde programação implementa a noção matemática de função: o cabeçalho deuma função descreve seu nome, seu domínio e seu contradomínio enquantoque o seu corpo descreve sua lei de formação. Por exemplo, o seguinte trechode código em Pascal

function dist (x1,y1: real; x2,y2:real):real;begin

dist := sqrt(sqr(x2-x1)+sqr(y2-y1));end;

descreve a função que calcula a distância entre dois pontos que possuem co-ordenadas (x1,y1) e (x2,y2). Note que o cabeçalho da função descreve o seudomínio (na forma do tipo de seus parâmetros formais) e seu contradomínio(no tipo de retorno da função). Ou seja, o cabeçalho da função Pascal dist éo equivalente da definição matemática dist : R×R×R×R→ R, onde a sua leide formação é dada por dist(x1,y1,x2,y2) =

√(x2−x1)2 +(y2−y1)2.

A diferença entre funções totais e funções parciais reside no fato de quenestas últimas nem todos os elementos do domínio são mapeados. Em umprograma, isso corresponde ao fato de que não existem saídas com significadopara todas as possibilidades de valores de entrada. O resultado da aplicaçãode uma função parcial a um elemento que não pertence ao seu domínio dedefinição (ou seja, que não é mapeado pela função) é indefinido, e usualmenterepresentado pelo símbolo ⊥.

Exemplo 8.2.4 (Função parcial) Seja a função f : N→ N definida como

f =

x+1 x mod 2 = 0

⊥ x mod 2 6= 0(1)

Na Figura 8.1 pode-se ver essa função graficamente representada. Note quesomente os elementos pares do domínio são mapeados para os seus respec-tivos sucessores no contradomínio da função.

397

Page 12: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.1. Exemplo de uma função parcial

Conforme a Definição 8.2.6, toda função parcial f pode ser decomposta emduas funções totais f ! e f ?, chamadas respectivamente funções de restriçãoe inclusão de f . Na sua definição, em (1), a função f tem como domínio oconjunto dos números naturais N, mas somente os elementos pares são efeti-vamente mapeados pela função. Se formarmos um conjunto destes elementosmapeados, que é um subconjunto do domínio original da função, então qual-quer função que seja igual a f para estes elementos será uma função total. Damesma forma, uma função de inclusão do conjunto dos números pares para oconjunto dos números naturais sempre pode ser construída.

Chama-se dom( f ) o conjunto que representa o domínio de definição dafunção f . Para o exemplo acima, dom( f ) = Pares ⊆ N, e a função de restriçãof ! : Pares → N é definida como f !(x) = x+ 1 = f (x). A função de inclusão f ? :Pares → N é dada por f ?(x) = x, ou seja, identifica os elementos do domíniode definição com eles mesmos no domínio da função f (note que o domíniode f ! e f ? é diferente do domínio de f ). A Figura 8.2 mostra graficamente adecomposição da função f definida acima nas funções f ! e f ?.

Funções podem apresentar propriedades em relação ao tipo de mapea-mento que realizam. Em particular, diz-se que uma função f : A→ B, total ouparcial, é

• injetora se a cada dois elementos distintos do domínio correspondemdois elementos distintos no contradomínio, ou seja, se para quaisquerx,y∈ dom( f ) então x 6= y→ f (x) 6= f (y);

• sobrejetora se todos os elementos do contradomínio encontram-se naimagem da função, ou seja, se para qualquer y∈ B existe algum x∈ A talque f (x) = y;

398

Page 13: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.2. Decomposição de uma função parcial emduas funções totais

• bijetora , se for simultaneamente injetora e sobrejetora.

8.2.2. Relações de ordem parcialOrdenações de elementos aparecem em todas as áreas do conhecimento

humano. Sempre que as palavras ’antes’ e ’depois’ aparecem em alguma fraseou contexto, temos uma ordem estabelecida sobre as entidades das quais seestá a falar. A construção matemática que representa uma ordenação é umarelação de ordem, que nada mais é do que uma relação transitiva entre oselementos que devem ser ordenados. Neste trabalho será usada uma relaçãode ordem parcial, que é um caso especial de uma relação de ordem, e queaparece com freqüência em muitos domínios da Ciência da Computação.

Definição 8.2.7 (Relação de ordem parcial) Uma relação binária R⊆ A×A éuma relação de ordem parcial se e somente se for reflexiva, antisimétrica etransitiva.

Exemplo 8.2.5 (Relações de ordem parcial) Algumas relações bem conhe-cidas são de ordem parcial. A seguir, alguns exemplos familiares:

• A relação 6 sobre o conjunto dos números reais é uma relação de or-dem parcial: para qualquer número x∈R tem-se que x6 x (reflexividade),para quaisquer três números reais x,y,z∈ R (não necessariamente dis-tintos), se x 6 y e y 6 z então x 6 z (transitividade) e para quaisquer doisnúmeros reais x,y ∈ R, sempre que x 6 y e y 6 x pode-se concluir quex = y (antissimetria). Esta relação é ainda uma relação de ordem total,visto que para quaisquer dois números reais x,y∈R, tem-se que ou x6 you y 6 x.

399

Page 14: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

• A relação ⊆ sobre conjuntos também é uma relação de ordem parcial:para qualquer conjunto A tem-se que A⊆ A (reflexividade), para quais-quer três conjuntos A, B e C, se A⊆B e B⊆C então A⊆C (transitividade)e para quaisquer dois conjuntos A e B, sempre que A⊆B e B⊆A pode-seconcluir que A = B (antissimetria). Diferentemente, contudo, da relação6, ela não é uma ordem total.

• A relação de subtipagem � em linguagens de programação (no sentidode possuir uma estrutura pertencente, totalmente ou em parte, a outrotipo) também é uma relação de ordem parcial: para qualquer tipo defi-nido pelo usuário T tem-se que T � T (reflexividade, visto que um tipo éestruturalmente idêntico a si próprio), para quaisquer três tipos T, T ′ eT ′′, se T � T ′ e T ′ � T ′′ então T � T ′′ (transitividade) e para quaisquerdois tipos T e T ′, sempre que T �T ′ e T ′ �T pode-se concluir que T = T ′

(antissimetria). Esta relação também não é uma ordem total.

Definição 8.2.8 (Conjunto parcialmente ordenado) Um conjunto parci-almente ordenado (ou simplesmente poset) Pv = 〈P,vP〉 é um conjunto Pjuntamente com uma relação de ordem parcial vP sobre P.

Funções entre conjuntos parcialmente ordenados em geral exigem que aordem existente entre os elementos seja preservada. Isso quer dizer que sedois elementos no domínio de definição da função estão ordenados, suas ima-gens devem estar ordenadas também. A definição formal desta construção,bem como alguns exemplos, encontram-se a seguir.

Definição 8.2.9 (Função monotônica) Sejam 〈P,vP〉 e 〈Q,vQ〉 dois conjun-tos parcialmente ordenados. Uma função f : P→Q é chamada função monotô-nica se e somente se, para quaisquer p, p′ ∈ P, se pvPp′ então f (p)vQ f (p′).

Exemplo 8.2.6 (Função monotônica) Uma função monotônica é uma funçãoque preserva a ordem dos elementos de seu domínio quando suas imagenssão comparadas usando a relação de ordem do seu contradomínio. A seguiralguns exemplos de função monotônicas e de funções não monotônicas, todasdefinidas sobre o conjunto parcialmente ordenado 〈Z,6〉 (os números inteirose a relação usual “menor ou igual” entre eles).

• Seja f : 〈Z,6〉 → 〈Z,6〉 a função cuja lei de formação é dada por f (x) =x+1. Esta função é monotônica, visto que para quaisquer dois númerosinteiros m,n ∈ Z, temos que, se m 6 n (isto é, se os elementos estãorelacionados na origem) então f (m) 6 f (n). É fácil provar que isso éverdade: se m6 n, f (m) = m+1 6 f (n) = n+1⇒ m+1 6 n+1⇒ m+1 6n+1⇒ m6 n (que é a premissa da nossa suposição, e logo é verdade).

• A função g(x) = |x| (módulo) contudo, não é uma função monotônica. Éfácil achar um contra-exemplo neste caso: sabe-se que −5 6 −2, con-tudo |−5|= 5 6/ 2 = |−2|.

400

Page 15: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

As definições dadas a seguir são pertinentes à teoria de ordem. A estruturagráfica de uma relação de ordem parcial é um grafo sem ciclos que passam pordois elementos distintos, visto que para uma relação ser de ordem parcial eladeve ser antissimétrica, o que exclui a existência de caminhos circulares decomprimento maior que 1 (um). Laços, contudo, são permitidos, visto que arelação também deve ser reflexiva.

Se temos uma estrutura gráfica desta forma, então faz sentido falar noselementos que estão ‘acima’ ou ‘abaixo’ de outros na relação, apesar de estestermos usualmente denotarem relações espaciais. Assim, se dado um con-junto parcialmente ordenado 〈P,vP〉, se temos elementos relacionados xvP y eyvP z, então x está ‘abaixo’ de y e z nesta relação, z está ‘acima’ de x e de y e yestá ‘entre’ x e z. As próximas definições dão conta da definição dos conjuntosdos elementos que estão ‘acima’ ou ‘abaixo’ de algum elemento (ou conjuntode elementos) dado.

Definição 8.2.10 (Conjunto superior, conjunto inferior) Seja 〈P,vP〉 umconjunto parcialmente ordenado. um subconjunto A⊆P é um conjunto superiorse sempre que x∈ A, y∈ P e xvP y tem-se que y∈ A. O conjunto superior de{x}, onde x∈ P (também chamado o conjunto de todos os elementos acima dex) é denotado por ↑ x.

Dualmente, um subconjunto A⊆ P é um conjunto inferior se x ∈ A implicaem y ∈ A para todo yv x. O conjunto de todos os elementos abaixo de umelemento x∈ A é denotado por ↓ x.

Definição 8.2.11 (Limitante superior, limitante inferior) Seja 〈P,vP〉 umconjunto parcialmente ordenado. Um elemento x ∈ P é dito um limitantesuperior de um subconjunto A⊆ P, escrito Av x, se e somente se av x paratodo a∈ A. O conjunto de todos os limitantes superiores de A é denotado porub(A)

Dualmente, um elemento x ∈ P é dito um limitante inferior de um subcon-junto A⊆ P, escrito xv A, se e somente se xv a para todo a∈ A. O conjunto detodos os limitantes inferiores de A é denotado por lb(A).

Definição 8.2.12 (Supremo (lub, join), ínfimo (glb, meet)) Seja 〈P,vP〉 umconjunto parcialmente ordenado. Se, para um subconjunto A⊆ P o seu con-junto de limitantes superiores possuir um menor elemento x, então x é cha-mado de menor limitante superior, ou supremo ou ainda join de A e escreve-sex = lub(A) ou x = tA.

Dualmente, se, para um subconjunto A ⊆ P o seu conjunto de limitantesinferiores possuir um maior elemento x, então x é chamado de maior limitanteinferior, ou ínfimo ou ainda meet de A e escreve-se x = glb(A) ou x = uA.

8.2.3. Grafos e morfismos de grafosOs cursos da área de Computação e Informática usualmente possuem dis-

ciplinas de Estruturas de Dados ou de Teoria dos Grafos onde estas estruturas

401

Page 16: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

são vistas. Supõe-se que o leitor já conhece estas estruturas, pelo menos demaneira superficial. A seguir apresenta-se o que é um grafo formalmente, ecomo estas estruturas podem ser relacionadas algebricamente.

Definição 8.2.13 (Grafo) Um grafo é uma tupla G= 〈V,E〉 onde V é o conjuntode nodos (ou vértices) do grafo e E ⊆V×V é uma relação binária sobre V. Oconjunto E é denominado conjunto de arcos (ou arestas) de G.

Um grafo pode então ser visto como um conjunto de elementos e uma rela-ção binária sobre estes elementos. Contudo, em alguns casos podemos quererrepresentar multigrafos, que são grafos que possuem mais do que uma arestaentre os mesmos dois nodos. Estas situações podem acontecer para mode-lar, por exemplo, caminhos diretos distintos entre a mesma origem e o mesmodestino, ou atributos diferentes de um mesmo objeto que têm o mesmo tipo.Neste caso, a Definição 8.2.13 não é adequada. A razão é que, sendo umarelação um conjunto, elementos iguais são identificados como sendo o mesmoelemento. Desta forma, duas arestas distintas, mas como mesma origem v edestino u, seriam representadas como o par ordenado (u,v). Como deixariade existir uma bijeção entre os arcos do grafo e o conjunto que os representa,não se pode reconstruir o grafo a partir de sua definição matemática. Logo,precisamos de uma definição formal que contemple esta situação.

Definição 8.2.14 (Grafo) Um grafo é uma tupla G = 〈VG, EG, srcG, tarG〉 ondeVG é um conjunto de vértices, EG é um conjunto de arcos, srcG : EG → VG é afunção que para cada arco retorna seu nodo de origem e tarG : EG → VG é afunção que para cada arco retorna seu nodo de destino.

A Definição 8.2.14 permite que um grafo tenha tantas arestas paralelasentre dois nodos quantas forem necessárias: note que o conjunto de arcosnão é mais uma relação binária sobre o conjunto de vértices, mas um conjuntoindependente deste, que serve para nomear as arestas. As funções src e tarrelacionam, para cada aresta e∈ E, os seus respectivos nodos de origem edestino.

Relações ou mapeamentos entre grafos podem ser expressos por morfis-mos. O termo morfismo é usado para expressar relacionamentos entre estru-turas algébricas, e nada mais é do que uma ou mais funções que preservam aestrutura que está sendo mapeada. As Definições 8.2.15 e 8.2.16 apresentam,respectivamente, o que se entende por um mapeamento total e um mapea-mento parcial de grafos.

Definição 8.2.15 (Morfismo total de grafos) Sejam G1 = 〈VG1, EG1, srcG1,tarG1〉 e G2 = 〈VG2, EG2, srcG2, tarG2〉 dois grafos. Sejam hV : VG1 → VG2 ehE : EG1 →EG2 duas funções totais. O par ordenado h = 〈hV ,hE〉 : G1→G2 é ummorfismo total de grafos entre G1 e G2 se e somente se hV ◦ srcG1 = srcG2 ◦hEe hV ◦ tarG1 = tarG2 ◦hE. Um morfismo total de grafos é dito injetor (sobrejetor,bijetor) se as suas funções componentes são injetoras (sobrejetoras, bijetoras).

402

Page 17: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.3. Circuito digital como um grafo rotulado

Definição 8.2.16 (Morfismo parcial de grafos) Seja G = 〈VG, EG, srcG, tarG〉um grafo. Um grafo S= 〈VS, ES, srcS, tarS〉 é dito um subgrafo de G, escrevendo-se S⊆ G ou S ↪→ G, se e somente se VS ⊆ VG, ES ⊆ EG, srcS = srcG|ES esrcS = tarG|ES. Um morfismo parcial de grafos h entre dois grafos G1 e G2 éum morfismo total de grafos de algum subgrafo dom(h) ↪→ G1 para G2. dom(h)é chamdo de domínio de h.

Um morfismo total ou parcial de grafos “preserva a estrutura” no seguintesentido: para qualquer aresta mapeada pelo morfismo, se verificarmos qual éseu nodo de origem no grafo de origem do mapeamento e depois mapearmoseste nodo, temos que chegar exatamente no mesmo lugar que chegaríamosse primeiro mapeássemos a aresta e daí verificássemos qual é o nodo de ori-gem da aresta mapeada no grafo destino. Esta correspondência deve existirtambém em relação aos nodos destino dos arcos mapeados.

Grafos podem ainda ser equipados com informações adicionais, que po-dem ser usadas para diferenciar certos tipos de nodos ou de arcos. Considere,por exemplo, o circuito apresentado na Figura 8.3. O desenho de um circuitolembra muito a estrutura de um grafo: pode-se imaginar que as entradas, assaídas e as portas lógicas são nodos e as ligações entre estas entidades sãoas arestas do grafo. No entanto, existe informação adicional sobre os nodos,necessários para diferenciá-los. Afinal, uma porta or é diferente de uma portaand, tanto em termos de representação quanto em termos operacionais.

Existem duas maneiras de representar tipos de nodos e de arestas em umgrafo: a primeira é utilizando um grafo rotulado, que contém informações sobrerótulos e funções de rotulação dos elementos do grafo; a segunda maneirautiliza grafos tipados, que são grafos ordinários mapeados para um grafo tipo

403

Page 18: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

via um morfismo total de grafos (Definição 8.2.15). A definição de grafo rotuladoé dada a seguir. A definição de grafo tipado é deixada para a Seção 8.3.2 ondeserá apresentado o conceito nos termos da orientação a objeto, que é o focodeste trabalho.

Definição 8.2.17 (Grafo rotulado) Um grafo rotulado G é uma tupla ordenadaG = (V,E,LV ,LE,src, tar, labV , labE) onde V é um conjunto de vértices, E é éum conjunto de arestas, LV e LE são, respectivamente, o conjunto de rótulosde vértices e de arestas, src, tar : E → V são funções, denominadas origem edestino, que associam a cada aresta do grafo G seus correspondentes nodosde origem e destino, labV : V → LV é a função de rotulação dos vértices elabE : E → LE é a função de rotulação dos arcos.

Exemplo 8.2.7 (Grafo rotulado) A Figura 8.3 apresenta um esquema de cir-cuito digital, contendo portas lógicas e conexões entre elas. Cada cone-xão liga exatamente duas portas, uma entrada a uma porta ou uma portaà saída. Sendo assim, pode-se representar a estrutura de um circuito ló-gico como um grafo. Nesta representação, as portas lógicas, as entradas ea saídas são os nodos enquanto que as conexões entre elas são as ares-tas do grafo. Formalmente, este grafo pode ser representado pelos conjun-tos V = {x1,x2,x3,x4,x5,x6,x7,x8,s, p1, p2, p3, p4, p5, p6, p7, p8} (vértices) e E ={a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17} (arestas) e pelasfunções src e tar descritas abaixo:

src(a1) = x1 src(a8) = x8 src(a15) = p6 tar(a4) = p2 tar(a11) = p6src(a2) = x2 src(a9) = p1 src(a16) = p7 tar(a5) = p3 tar(a12) = p7src(a3) = x3 src(a10) = p2 src(a17) = p8 tar(a6) = p3 tar(a13) = p7src(a4) = x4 src(a11) = p3 tar(a7) = p4 tar(a14) = p8src(a5) = x5 src(a12) = p3 tar(a1) = p1 tar(a8) = p4 tar(a15) = p8src(a6) = x6 src(a13) = p4 tar(a2) = p1 tar(a9) = p5 tar(a16) = p8src(a7) = x7 src(a14) = p5 tar(a3) = p2 tar(a10) = p5 tar(a17) = s

No entanto, uma porta NAND é diferente de uma porta OR, por exemplo. Asaída de uma porta depende das suas entradas e de qual porta lógica estamosfalando. Assim, embora conexões entre portas, entradas e saídas sejam sem-pre idênticas, os nodos do grafos pertencem a classes de elementos distintas.

Podemos inserir esta informação adicional em um grafo por meio de rótulos.Tanto arestas quando vértices podem ser rotulados, embora neste caso só façasentido rotular os nodos, que são os elementos que efetivamente devem conterinformação adicional. No caso deste circuito lógico, pode-se criar o conjuntode rótulos Portas = {OR,AND,NAND,NOR,XOR,NOT,entrada,saída}, e umafunção que, para cada nodo, devolva o seu rótulo correspondente. Para o grafoda Figura 8.3, a função de rotulação dos nodos labV : V → Portas é dada por

404

Page 19: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

labV(x1) = entrada labV(x7) = entrada labV(p4) = NANDlabV(x2) = entrada labV(x8) = entrada labV(p5) = ORlabV(x3) = entrada labV(s) = saída labV(p6) = NOTlabV(x4) = entrada labV(p1) = NAND labV(p7) = ANDlabV(x5) = entrada labV(p2) = AND labV(p8) = ORlabV(x6) = entrada labV(p3) = NOR

A rotulação dos arcos, visto que todos eles correspondem à mesma entidadelógica, é dada por uma função labE : E→{•} que tem como domínio o conjuntode arcos do grafo e como contradomínio um conjunto unitário. Para todo arcoe∈ E, labE(e) = •, o que significa que todos os arcos possuem o mesmo rótulo.Desta forma, a informação relevante sobre o tipo de cada porta é carregadajunto ao grafo, que pode ser reconstruído a partir de sua definição matemática.

Da mesma forma que relações (Definição 8.2.3) não precisam necessa-riamente ser binárias, também arcos de um grafo não necessitam conectarsomente dois nodos (um de origem e outro de destino). Um grafo cujos arcosrepresentam relacionamentos entre elementos de um conjunto (os nodos, nocaso) pode ser visto como uma relação binária sobre esse conjunto. Se quiser-mos implementar visualmente uma relação de aridade maior, precisamos danoção de hipergrafo. Um hipergrafo é um grafo onde os arcos não se restrin-gem a ter exatamente um nodo de origem e outro nodo de destino. Os arcos deum hipergrafo, denominados hiperarcos, podem ter qualquer número de nodosde origem e qualquer número de nodos de destino, inclusive zero.

Para definirmos formalmente um hipergrafo, precisamos de algumas de-finições tiradas da teoria de linguagens formais. A noção de seqüência desímbolos de um alfabeto é uma delas.

Definição 8.2.18 (Alfabeto, string) Um alfabeto Σ é qualquer conjunto finitode símbolos. Uma string ou palavra w sobre o alfabeto Σ é uma seqüência desímbolos w1 . . .wn, n > 0, onde cada wi ∈ Σ, i = 1, . . . ,n. Uma seqüência de zeroelementos sobre Σ é chamada palavra vazia e é denotada pelo símbolo ε. Oconjunto de todas as strings finitas sobre Σ é denotado por Σ∗.

Definição 8.2.19 (Hipergrafo) Um hipergrafo H é uma tupla 〈VH , EH , srcH ,tarH〉 onde VH é um conjunto de vértices, EH é um conjunto de (hiper)arcose srcH , tarH : EH → V∗

H são, respectivamente, as funções de origem e destinodos hiperarcos.

Os elementos de V∗H são strings sobre o conjunto VH , que é considerado

um alfabeto como na Definição 8.2.18. Um hipergrafo é uma generalização deum grafo para suportar relações de aridade maior que 2 (binárias). Concre-tamente, a diferença de um hipergrafo para um grafo definido da forma usual(Definição 8.2.14) é que os arcos do primeiro (denominados hiperarcos) podemter vários (ou nenhum) nodo de origem e/ou destino.

405

Page 20: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.4. Exemplo de hipergrafo

Exemplo 8.2.8 (Hipergrafo) A Figura 8.4 mostra um exemplo de hipergrafo.Aqui, os nodos são representados por retângulos vazados e os hiperarcos porquadrados preenchidos e suas ligações com seus nodos de origem e des-tino. Os nodos origem ligam-se ao hiperarco com linhas cheias, enquanto queo hiperarco conecta-se ao(s) seu(s) nodo(s) destino através de setas. Nesteexemplo, para o hiperarco H apresentado, o conjunto de nodos VH contémsete elementos, a saber {n1,n2,n3,n4,n5,n6,n7}. O conjunto de hiperarcosEH = {h1,h2,h3} contém três elementos. As funções de origem (srcH : EH →V∗

H )e destino (tarH : EH →V∗

H ) dos hiperarcos são definidas como se segue:

srcH(h1) = n1 tarH(h1) = n3srcH(h2) = n1 n3 tarH(h2) = n2 n4 n4srcH(h3) = n5 n7 tarH(h3) = n4 n6

Morfismos totais e parciais de hipergrafos podem ser definidos da mesmaforma que para grafos, a única diferença é que agora os mapeamentos dearcos devem preservar uma seqüência de nodos, que é verificada nodo a nodo,conforme as Definições 8.2.20 e 8.2.21.

Definição 8.2.20 (Morfismo total de hipergrafos) Sejam H1 = 〈VH1, EH1,srcH1, tarH1〉 e H2 = 〈VH2, EH2, srcH2, tarH2〉 dois hipergrafos. Sejam hV :VH1 →VH2

e hE : EH1 → EH2 duas funções totais, onde h∗V : V∗H1

→ V∗H2

é a extensãoda função hV para strings, tal que, para qualquer string w = w1 . . .wn ∈ V∗

H1,

h∗V(w) = hV(w1)hV(w2) . . .hV(wn), n > 0. O par h = 〈hV ,hE〉 : H1 → H2 é um mor-fismo total de hipergrafos entre H1 e H2 se e somente se h∗V ◦srcH1 = srcH2 ◦hE

406

Page 21: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

e h∗V ◦ tarH1 = tarH2 ◦hE. Um morfismo total de hipergrafos é dito ser injetor (so-brejetor, bijetor) se as suas funções componentes forem injetoras (sobrejetoras,bijetoras).

Definição 8.2.21 (Morfismo parcial de hipergrafos) Seja H = 〈VH , EH , srcH ,tarH〉 um hipergrafo. Um hipergrafo S= 〈VS, ES, srcS, tarS〉 é dito um subgrafode H, escrito S⊆H ou S↪→H, se e somente se VS⊆VH , ES⊆ EH , srcS = srcH |ES

e srcS = tarH |ES. Um morfismo parcial de hipergrafos h entre dois hipergrafosH1 e H2 é um morfismo total de hipergrafos entre algum subgrafo dom(h) ↪→ H1e H2. dom(h) é chamado de domínio de definição de h.

Hipergrafos rotulados e morfismos entre esses hipergrafos podem ser defi-nidos nos mesmos moldes das definições destas estruturas para grafos. Estetrabalho é deixado como exercício para o leitor, mas deve ser uma aplicaçãodireta dos conceitos e definições já apresentados.

8.3. Grafos orientados a objeto8.3.1. Grafos de classes

Linguagens de programação orientadas a objeto podem implementar di-ferentes estruturas hierárquicas de classes (nas abordagens baseadas emclasses [Cook 1990]) ou objetos (nas abordagens baseadas em objetos[Ungar et al. 1991]), dependendo do tipo de herança implementada e da exis-tência de uma classe da qual todas as outras derivam. A herança pode sersimples ou múltipla, dependendo do número de classes das quais uma novaclasse pode derivar. Na herança simples, uma classe pode ser a extensãode no máximo uma outra classe, enquanto que na herança múltipla uma novaclasse pode derivar de quantas classes quiser. Linguagens que implemen-tam herança simples diferem no sentido de todas as classes possuírem umaclasse primitiva comum (como a classe Object, em Java [Campione et al. 2000]e Delphi [Lischner 2000]) ou não (como Ada95 [Barnes 1998], ou Glass[Muhammad and Ferreira 2003]). O mesmo acontece com linguagens que per-mitem herança múltipla, com uma classe primitiva comum (Eiffel [Meyer 1991])ou sem ela (C++ [Stroustup 2000]).

Grafos acíclicos representam fielmente a estrutura de classes em uma lin-guagem orientada a objeto que permite herança múltipla, enquanto que lin-guagens que permitem somente herança simples têm esta estrutura melhorrepresentada por um conjunto de árvores, que são casos particulares de gra-fos acíclicos. A ausência de ciclos, isto é, da existência de um caminho decomprimento maior que zero entre um nodo e ele mesmo, é consistente tantocom a criação de classes por herança quanto com a sobrescrita de métodosem linguagens orientadas a objeto: uma classe, para ser definida como umaespecialização (derivação) de outra, necessita que a classe primitiva já existaantes que ela seja criada. De maneira similar, um método só pode sobrescre-ver (redefinir) outro método se o segundo já existir em alguma classe primitivadaquela que o sobrescreve. Assim, nem classes podem ser derivadas nem

407

Page 22: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

métodos podem ser sobrescritos de forma circular. Da mesma forma, não faztambém sentido que uma classe seja uma especialização de si mesma ou queum método seja uma redefinição de si próprio.

A definição de uma relação estrita, apresentada a seguir na Definição 8.3.1,formaliza o que deve ser a organização hierárquica fundamental das classesem linguagens orientadas a objeto de modelagem ou programação, quandosomente herança simples for permitida2.

Definição 8.3.1 (Relação estrita) Uma relação binária R⊆ A×A é dita umarelação estrita se e somente se apresentar as seguintes propriedades:

1. se (a,a′) ∈ R então a 6= a′ (R é irreflexiva);

2. se (a,a1),(a1,a2), . . . ,(an−1,an),(an,a′) ∈ R, n > 0, então (a′,a) /∈ R (R éacíclica);

3. para quaisquer a,a′,a′′ ∈ A, se (a,a′),(a,a′′) ∈ R então a′ = a′′ (R é umafunção);

4. para todo a ∈ A, ou (a,b) /∈ R para todo b ∈ A ou então existe n > 0 talque se (a,a1),(a1,a2), . . . ,(an−1,an) ∈ R, então (an,b) /∈ R para todo b∈ A(todas as cadeias em R são finitas).

As duas primeiras condições expressam a ausência de laços e ciclos naestrutura, conforme discutido nos parágrafos anteriores. A terceira condiçãoassegura que a herança simples é implementada, isto é, uma classe é uma es-pecialização de, no máximo, alguma outra classe. A exclusão dessa condiçãoé suficiente para representar hierarquias de classes que implementam herançamúltipla. A quarta condição tem significado teórico e quer dizer que não podeexistir uma cadeia infinita de classes das quais uma classe é derivada. Es-pecificações orientadas a objeto são necessariamente finitas (como todas ascoisas reais são), então essa condição não influi no processo de definição dasclasses de um modelo. A Figura 8.5 apresenta um exemplo de uma relaçãoestrita. Os nomes constituem os elementos do conjunto base A e as setaspontilhadas representam a relação R.

A relação que representa a hierarquia de herança em um programa ori-entado a objeto é constituída como uma relação estrita. Contudo, esta hie-rarquia também tem características de transitividade, visto que se uma classex deriva de uma classe y e se esta classe y deriva de uma terceira classe zentão x também deriva da classe z. Quando queremos construir uma rela-ção transitiva a partir de uma relação que não tem esta propriedade, constrói-se um fecho. Para os propósitos deste texto, será construído o fecho tran-sitivo e reflexivo da relação. O fecho transitivo e reflexivo de uma relação

2 Muitos resultados deste trabalho são estendidos trivialmente para herança múltipla. Aherança simples, contudo, além de mais familiar aos programadores, facilita o entendi-mento das definições aqui apresentadas.

408

Page 23: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.5. Exemplo de uma relação estrita

é a relação adicionada dos pares que faltam para que ela se torne uma re-lação transitiva e reflexiva. Especificamente, para uma relação vP, seu fe-cho reflexivo é vP ∪ {(x,x) | x ∈ P}, ou seja todos os pares que contém oselementos relacionados com eles mesmos. O fecho transitivo é construídocomo vP ∪ {(x,y) | ∃z1, . . . ,zk ∈ P : (x,z1),(z1,z2) . . . ,(zk−1,zk),(zk,y) ∈ vP}, istoé, é completado pelos pares necessários para tornar a relação transitiva. OExemplo 8.3.1 mostra a construção do fecho reflexivo e transitivo da relaçãoestrita apresentada na Figura 8.5.

Exemplo 8.3.1 (Fecho transitivo e reflexivo) A relação estrita vP apresen-tada na Figura 8.5 possui um conjunto base P = {Natural, Integer, Real,Complex, Figure, Color, shape, square, round, triangle, circle, ellipse} e arelação estrita em si é dada pelo conjunto de pares vP = {(Natural,Integer),(Integer, Real), (Real, Complex), (square, shape), (round, shape), (triangle,shape), (circle, round), (ellipse, round)}, conforme indicam as setas na figuraque representam essa relação. Para construirmos um conjunto estritamenteordenado Pv = 〈P,v∗

P〉 desta relação, precisamos construir o fecho transitivo ereflexivo de vP.

O fecho reflexivo é construído adicionando todos os pares {(x,x) | x∈ P} àrelação original, ou seja, adicionando o conjunto {(Natural, Natural), (Integer,Integer), (Real, Real), (Complex, Complex), (Figure, Figure), (Color, Color),(shape, shape), (square, square), (round, round), (triangle, triangle), (circle,circle), (ellipse, ellipse)} à relação. Na Figura 8.5 isso seria equivalente a adi-cionar laços em todos os elementos do conjunto.

O fecho transitivo é construído adicionando os pares que faltam para tor-nar a relação transitiva. Lembrando a sua definição, uma relação é transitivasempre que (x,y) e (y,z) forem pares da relação, tem-se que (x,z) tambémprecisa ser um par da relação. Assim, na Figura 8.5, como (Integer, Real) éum par da relação e como (Real, Complex) também é, tem-se que o par (In-teger, Complex) deve ser adicionado à relação. Fazendo isso com todos ospares (direta e indiretamente, conforme a definição), deve-se adicionar o con-junto {(Natural, Real), (Integer, Complex), (Natural, Complex), (circle, shape),

409

Page 24: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.6. Fecho reflexivo e transitivo da relação da Figura 8.5

(ellipse, shape)} à relação original.O fecho transitivo da relação apresentada na Figura 8.5 é o conjunto

{(Natural,Integer), (Integer, Real), (Real, Complex), (square, shape), (round,shape), (triangle, shape), (circle, round), (ellipse, round), (Natural, Real), (In-teger, Complex), (Natural, Complex), (circle, shape), (ellipse, shape), (Natural,Natural), (Integer, Integer), (Real, Real), (Complex, Complex), (Figure, Figure),(Color, Color), (shape, shape), (square, square), (round, round), (triangle, trian-gle), (circle, circle), (ellipse, ellipse)}. A representação gráfica do fecho transi-tivo e reflexivo da relação vP é apresentado na Figura 8.6.

Pode-se mostrar que o fecho transitivo e reflexivo de uma relação estrita éuma relação de ordem parcial (Definição 8.2.7). Este fato permite que todos osresultados da teoria de ordens parciais sejam usados na investigação de pro-priedades de especificações orientadas a objeto. Embora este fato não sejaexplorado em detalhe neste texto, podemos usá-lo para definir formalmentecomposições e extensões de sistemas orientados a objeto, o que é importantese quisermos descrever reutilização e combinação de tais sistemas. Este re-sultado também será importante na construção de computações de sistemasorientados a objeto especificados com grafos. Maiores detalhes podem serencontrados em [Ferreira and Ribeiro 2005].

Relações estritas serão então usadas para representar duas estruturas hie-rárquicas distintas: herança e sobrescrita. Como essas relações são definidassobre conjuntos (de classes e de métodos de classe, respectivamente), deve-mos definir então o que será chamado de conjunto estritamente ordenado, quenada mais é do que um conjunto equipado com uma relação deste tipo.

Definição 8.3.2 (Conjunto estritamente ordenado) Um conjunto estrita-mente ordenado Pv é um par 〈P,v∗

P〉 onde P é um conjunto, vP é uma relação

410

Page 25: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

estrita e v∗P é o fecho transitivo e reflexivo desta relação.

Conjuntos estritamente ordenados são um caso especial de conjuntos par-cialmente ordenados, onde a relação de ordem parcial subjacente ao conjuntoé gerada pelo fecho transitivo e reflexivo de uma relação estrita.

Talvez a maneira mais intuitiva de modelar sistemas orientados a objetocom grafos é representar as classes e os objetos como nodos e os atributos emensagens como arcos. Um sistema orientado a objeto consiste em um con-junto de instâncias — objetos — de classes definidas previamente. Cada objetopossui uma estrutura interna definida pelos seus atributos e se comunica comoutros objetos usando troca de mensagens, que na maioria das linguagensorientadas a objeto modernas é implementada como invocação de métodos.

Os grafos usados para modelar estes sistemas devem, então, refletir essaestrutura. A definição das classes será feita na forma de um grafo, onde cadanodo é um identificador da classe, hiperarcos partindo dos nodos represen-tam os atributos da classe e hiperarcos chegando na classe representam asmensagens que se pode enviar a elas, isto é, seus métodos. A hierarquia deherança é construída por uma relação estrita entre os nodos do grafo. A indi-cação de quais métodos são redefinidos e que métodos os redefinem tambémé indicada por uma relação deste mesmo tipo nos hiperarcos que represen-tam mensagens. Estas relações são necessárias na especificação, para queo polimorfismo de subclasses e a ligação dinâmica de métodos possam sermodelados adequadamente nos programas que usam grafos. O grafo resul-tante é denominado grafo de classes e sua definição formal é apresentada naDefinição 8.3.3, a seguir.

Notação: No que se segue, um pequeno abuso de notação é utilizado: paraqualquer conjunto S, S+ denota o seu fecho transitivo e S∗ denota seu fechotransitivo e reflexivo com respeito à operação de concatenação (ou seja, to-das as listas finitas formadas por elementos de S). Um elemento s∈ S∗ re-presenta uma lista finita de elementos (que podem ser repetidos) de S, en-quanto que s∈ Ssignifica ou um único elemento de Sou uma lista que contémum único elemento de S. Este abuso é também utilizado em diversos livrosde Linguagens Formais (como [Lewis and Papadimitriou 1998], [Martin 1996],e [Hopcroft et al. 2001]).

Definição 8.3.3 (Grafo de classes) Um grafo de classes é uma tupla 〈Vv, Ev,L, src, tar, lab〉 onde Vv = 〈V,v∗

V〉 é um conjunto estritamente ordenado devértices, Ev = 〈E,v∗

E〉 é um conjunto estritamente ordenado de hiperarcos,L = {attr,msg} é um conjunto de dois rótulos de arcos, src, tar : E → V∗ sãoduas funções monotônicas, chamadas respectivamente de funções de origem(source) e destino (target), lab : E → L é a função de rotulação dos hiperarcos,tal que as seguintes restrições sejam atendidas:

Restrições estruturais: para todo hiperarco e∈ E, as seguintes propriedadessão verdadeiras:

411

Page 26: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

• se lab(e) = attr então src(e) ∈ V e tar(e) ∈ V∗ (se e é um arco deatributo então ele tem exatamente um nodo de origem) e

• se lab(e) = msg então src(e) ∈ V∗ e tar(e) ∈ V (se e é um arco demensagem então ele tem exatamente um nodo de destino).

Os conjuntos {e∈ E | lab(e) = attr} (conjunto de todos os atributos) e{e∈ E | lab(e) = msg} (conjunto de todas as mensagens) são denotadospor E|attr e E|msg, respectivamente.

Restrições sobre as relações de ordem: para todo hiperarco e∈ E, as se-guintes propriedades são verdadeiras:

1. se (e,e′) ∈ vE então lab(e) = lab(e′) = msg,

2. se (e,e′) ∈ vE então src(e) = src(e′),

3. se (e,e′) ∈ vE então (tar(e), tar(e′)) ∈ v+V , e

4. se (e′,e) ∈ vE e (e′′,e) ∈ vE , com e′ 6= e′′, então (tar(e′), tar(e′′)) /∈v∗

V e (tar(e′′), tar(e′)) /∈ v∗V .

Definições formais nem sempre são de fácil leitura, mas são necessáriaspara descrever sem ambigüidades o que se está tentando dizer. No casoacima, estamos descrevendo, usando estruturas matemáticas também defi-nidas formalmente, o tipo de estrutura que vai representar as classes de umsistema orientado a objeto. Sempre que se quer transmitir uma informaçãosem ambigüidade, o melhor é usar algum domínio matemático. Matemática,no âmbito da Ciência da Computação também é uma linguagem, e como taldeve ser entendida. Como qualquer linguagem, requer algum estudo e prá-tica para ser dominada, então é sempre louvável tentar entender as definiçõesapresentadas neste texto. Após algum tempo e algum esforço, estas definiçõesvão se tornando cada vez mais claras. No parágrafo a seguir, a Definição 8.3.3é explicada em detalhe.

Grafos de classes são os grafos usados para modelar a organização dasclasses em sistemas orientados a objeto. Cada nodo do grafo é um identifi-cador de uma classe, os hiperarcos que saem dos nodos são os atributos daclasse e os hiperarcos que chegam em um nodo são as mensagens que po-dem ser endereçadas à classe. Cada hiperarco é rotulado como um elementodo conjunto de rótulos (attr ou msg), e este rótulo serve para diferenciar qualé o tipo do hiperarco, visto que tanto atributos como mensagens são elemen-tos do conjunto de hiperarcos. As restrições estruturais representam o fatode que um atributo pertence a uma única classe — se o hiperarco é rotuladocomo atributo então possui uma única origem — e que uma mensagem (mé-todo) também pertence a uma única classe. Um atributo que contém mais doque um vértice de destino pode ser visto como um registro (record ou struct),ou seja, um único nome que representa de fato um agrupamento de valoresde um mesmo tipo ou de tipos diferentes; os nodos origem de um hiperarco

412

Page 27: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

de tipo mensagem são os parâmetros passados para aquela mensagem. Umhiperarco de tipo mensagem define então a assinatura de um método.

As hierarquias de herança e sobrescrita são definidas pelas relações estri-tas (Definição 8.3.2) existentes, respectivamente, sobre os conjuntos de nodose de hiperarcos. Como estas relações são funcionais, então restringe-se àherança simples. A relação de sobrescrita existente sobre o conjunto de hi-perarcos identifica quais são os métodos que estão sendo redefinidos e porquais métodos eles são sobrescritos. As restrições existentes sobre esta rela-ção de ordem asseguram que os métodos são sobrescritos de acordo com opermitido pelo paradigma, isto é, somente hiperarcos que representam mensa-gens (rotulados como msg) podem ser sobrescritos (1), seus parâmetros sãoidênticos (2), o método que está sendo sobrescrito existe em uma classe pri-mitiva estritamente acima (na relação de herança) daquela que o sobrescreve(3) e somente a mensagem mais próxima na relação de sobrescrita pode serredefinida (4).

Notação: A partir deste ponto, todos os grafos apresentados em formato gráficoseguirão a seguinte notação:

• Os vértices de um grafo serão representados por retângulos vazados,contendo o nome do nodo.

• Os hiperarcos de tipo atributo serão representados por um quadrado pre-enchido colado ao retângulo que representa o seu nodo de origem; osnodos de destino do hiperarco são indicados por setas que partem doquadrado que identifica o hiperarco.

• Os hiperarcos de tipo mensagem são identificados pelo símbolo <A.

• Os tentáculos (setas que partem do quadrado que identifica o hiperarco)dos hiperarcos são nomeados para facilitar a leitura e o entendimentodos grafos apresentados.

• A relação estrita de herança entre os nodos é indicada pelas setas tra-cejadas que ligam os nodos.

• A relação estrita de redefinição de mensagens é indicada pelas sejaspontilhadas que ligam os hiperarcos deste tipo.

Exemplo 8.3.2 (Grafo de classes) A Figura 8.7 apresenta um grafo de clas-ses muito simples para figuras e formas geométricas. Os nodos do grafo re-presentam as classes (Shape, Round, Circle, Ellipse, Figure, Drawing, Color eInteger) enquanto que os atributos e mensagens são representados pelos hi-perarcos. A relação de herança é representada pelas setas tracejadas, emborasomente a relação estrita subjacente esteja desenhada, para facilitar o enten-dimento e a visualização. A relação completa de herança é dada pelo fechotransitivo e reflexivo desta relação, conforme explicado no Exemplo 8.3.1, e arelação de sobrescrita de métodos está representada pelas linhas pontilhadas.

413

Page 28: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.7. Grafo de classes para formas geométricas

A classe Figure possui um atributo denominado consists, cujo destino é onodo Shape. Isso significa que o tipo do atributo é um elemento da classeShape. A classe Shape, por sua vez, possui um atributo que é um hiperarcocom três tentáculos de destino, o que significa que este atributo agrupa três ele-mentos de dados. Um tentáculo denominado color, que deve ser um elementoda classe Color e dois atributos denominados pos-x e pos-y que são amboselementos da classe Integer. A classe Shape é especializada via herança naclasse Round, que por sua vez é especializada nas classes Circle e Ellipse.Note como a redefinição do método Draw da classe Shape pelas classes Cir-cle e Ellipse é compatível com as restrições impostas na relação de sobrescritaexistentes na Definição 8.3.3.

8.3.2. Grafos tipadosClasses são representadas como nodos de um grafo de classes e seus

métodos e atributos como hiperarcos, conforme visto na Seção 8.3.1. Umacoleção de objetos, juntamente com seus atributos e mensagens endereçadasa eles (isto é, um programa orientado a objeto) pode ser caracterizado comoum grafo tipado sobre um grafo de classes. Tipar um grafo nada mais é doque identificar cada um de seus elementos (nodos e arcos) com algum nodoe algum arco de um outro grafo. Neste caso, deve-se identificar os elemen-tos de um grafo que representa uma instância de um objeto em um programaorientado a objeto com os elementos de um grafo de classes específico, vistoque os objetos de um programa são de alguma classe definida neste mesmoprograma. Grafos tipados [Corradini et al. 1996] são uma ferramenta poderosapara especificação de sistemas via grafos. A tipagem que apresentamos aqui

414

Page 29: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

é uma generalização daquela, para que as construções da programação orien-tada a objeto possam ser implementadas. O leitor interessado é convidado acomparar as duas abordagem para ver a diferença [Ferreira and Ribeiro 2003].

Notação: Para qualquer conjunto parcialmente ordenado 〈P,vP〉, um conjuntoparcialmente ordenado induzido 〈P∗,vP∗〉 pode ser construído, tal que paraquaisquer duas seqüências de símbolos u= u1 . . .un,v= v1 . . .vn∈P∗ tem-se queuvP∗ v se e somente se |u|= |v| (ambas as seqüências têm o mesmo compri-mento) e ui vP vi , i = 1, . . . , |u| (os elementos correspondentes das seqüênciasestão relacionados via herança). Se Pv e Qv forem conjuntos parcialmenteordenados, qualquer função monotônica (isto é, que preserva a ordem doselementos mapeados, Definição 8.2.9) f : P→ Q pode ser estendida à funçãomonotônica f ∗ : P∗→Q∗, com f ∗(p1 . . . pn) = f (p1) f (p2) . . . f (pn) = q1 . . .qn ondep1 . . . pn ∈ P∗ and q1 . . .qn ∈Q∗ (ou seja, a função estendida f ∗ transforma cadaelemento da seqüência no elemento em que a função f o transformaria).

A definição de morfismo de tipagem, apresentado a seguir na Defini-ção 8.3.4, nada mais é do que a identificação dos elementos de um grafo qual-quer com os elementos do grafo de classes que representa a hierarquia declasses em uma especificação. Como cada objeto em um programa orientadoa objeto é definido como tendo exatamente um tipo, então matematicamenteesse mapeamento pode ser representado por uma função. O nome “morfismo”é usado em matemática para quando se estabelece relacionamentos entre es-truturas matemáticas, e não deve ser encarado como uma dificuldade, mascomo um outro nome (mais técnico) para estes relacionamentos.

Definição 8.3.4 (Grafo C-tipado) Um grafo C-tipado GC é uma tupla 〈G, t,C〉,onde C = 〈VCv, ECv, L, srcC , tarC , labC〉 é um grafo de classes, G = 〈VG, EG,srcG, tarG〉 é um hipergrafo e t é um par de funções totais 〈tV : VG → VC , tE :EG → EC〉 tais que (t∗V ◦srcG)vV∗

C(srcC ◦ tE) e (t∗V ◦ tarG)vV∗

C(tarC ◦ tE).

Segundo a definição Definição 8.3.4, tem-se então um hipergrafo G queconsta de um conjunto de vértices, um conjunto de hiperarcos e as funçõesde origem e destino dos hiperarcos. Note que G não possui relações sobreseus nodos e hiperarcos, assim como estes últimos também não são rotuladoscomo atributos ou mensagens. Toda essa informação será inferida quando umelemento de G for identificado com um dos elementos do grafo de classes C,que contém essa informação. Da mesma forma, quando se define um objetoem um programa orientado a objeto, a informação sobre a classe do objeto édada pela declaração do seu tipo. O mapeamento de tipagem em si é feitopor duas funções, que mapeiam separadamente os vértices e arcos dos gra-fos chamadas, respectivamente, de tV : VG → VC e tE : EG → EC . Note que aprimeira função tem como domínio o conjunto de vértices do grafo G e comocontradomínio o conjunto de vértices do grafo de classes C, enquanto que a

415

Page 30: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

segunda função tem como domínio o conjunto de hiperarcos do grafo G e comocontradomínio o conjunto de hiperarcos do grafo de classes C.

As restrições impostas às funções tV (que mapeia os vértices) e tE (quemapeia os hiperarcos) visam estabelecer a herança de atributos e métodos doparadigma. Apesar das expressões parecerem complicadas à primeira vista,seu significado é trivial: um arco e de um grafo C-tipado pode ter como origem(respectivamente, destino) qualquer nodo v do mesmo grafo desde que sejatipado sobre um arco do grafo de classes (via a função tE, ou seja, o tipo doarco é tE(e)) que tenha como origem (respectivamente, destino) um nodo como qual v esteja relacionado via herança. Esta definição reflete o fato de que umobjeto pode fazer uso de qualquer atributo (ou mensagem) que pertença a umade suas classes primitivas, visto que tal elemento é herdado quando a classeé especializada. O Exemplo 8.3.3 ilustra essa situação.

Exemplo 8.3.3 (Grafo C-tipado) A Figura 8.8 mostra o grafo C-tipado G =〈{F,Egg,2,5,White},{1,2},src, tar〉 sobre o grafo de classes C da Figura 8.7.Os tentáculos dos hiperarcos são nomeados para facilitar a visualização sema necessidade de setas explícitas, para não poluir o diagrama. Os tentáculosdo hiperarco 2 são chamados color, pos-x e pos-y; o único tentáculo do hipe-rarco 1 é denominado consists. Note que um objeto da classe Figure deve terum atributo (hiperarco 1) do tipo Shape. O atributo do objeto F, contudo, é dotipo Ellipse. Mas isso é permitido pelo morfismo de tipagem, visto que a classeEllipse está relacionada por herança com a classe Shape. A classe Ellipse, poroutro lado, não possui nenhum atributo no grafo C-tipado da Figura 8.7. Mas,como uma Ellipse é uma classe Shape especializada, ela herda todos os seusatributos, o que significa que o grafo está bem tipado.

A seguir é mostrado como o grafo está bem tipado (de acordo com suadefinição):

(t∗V ◦src)(1) = Figure vV∗C

Figure= (srcC ◦ tE)(1)(t∗V ◦ tar)(1) = Ellipse vV∗

CShape= (tarC ◦ tE)(1)

(t∗V ◦src)(2) = Ellipse vV∗C

Shape= (srcC ◦ tE)(1)(t∗V ◦ tar)(2) = Color Integer Integer vV∗

CColor Integer Integer= (tarC ◦ tE)(1)

Relações entre grafos C-tipados podem ser definidas em termos de morfis-mos entre estas estruturas. As relações existentes devem preservar a origeme o destino dos arcos, bem como as relações de herança e sobrescrita do grafode classes subjacente.

Definição 8.3.5 (Morfismo de grafo C-tipado) Sejam GC1 = 〈G1, t1,C〉 e GC

2 =〈G2, t2,C〉 dois grafos C-tipados sobre o mesmo grafo de classes C = 〈Vv, Ev,L, src, tar, lab〉. Um morfismo de grafos C-tipados h : GC

1 →GC2 entre os grafos

GC1 e GC

2 , é um par de funções parciais h = 〈hV : VG1 →VG2,hE : EG1 → EG2〉 talque h é um morfismo parcial de hipergrafos (Definição 8.2.21) e para todos os

416

Page 31: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.8. Exemplo de um grafo C-tipado

elementos v∈ dom(hV), (t2V ◦hV)(v) vVCt1V(v), e para todos os elementos e∈

dom(hE), (t2E ◦hE)(e)vECt1E(e). Se (t2E ◦hE)(e) = t1E(e) para todo e∈ dom(hE)

então o morfismo é dito estrito.

Um morfismo de grafo C-tipado permite que sejam relacionados elemen-tos desde que estes elementos estejam relacionados (direta ou indiretamente)pelas relações de herança (no caso do nodos) ou de sobrescrita (no caso dohiperarcos). O significado da ligação de dois elementos x 99K y pela relação deherança é a usual em programa orientado a objeto: em qualquer lugar onde umelemento de tipo3 y for esperado, um elemento de tipo x pode aparecer, visto

3 A palavra tipo é usada aqui em um sentido menos restrito do que aquele usado namaioria dos textos de projeto de linguagens de programação. Apesar de existir defato uma diferença entre as hierarquias de herança e de subtipagem entre objetos[Cook et al. 1989], tal distinção não será levada em consideração aqui, visto que es-tamos trabalhando em um nível mais alto de abstração. Espera-se que isso não seja

417

Page 32: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

que um objeto de tipo x é também um objeto de tipo y. Um morfismo de grafosC-tipados reflete este conceito, uma vez que dois nodos podem ser identifica-dos pelo morfismo desde que seus tipos, pertencentes ao grafo de classes,estejam conectados via relação de herança. De forma similar, dois arcos po-dem ser relacionados pelo morfismo se seus tipos estiverem relacionados viarelação de sobrescrita. Como um arco de atributo somente está relacionado nofecho transitivo e reflexivo da relação de sobrescrita consigo mesmo (de acordocom a Definição 8.3.3), ele somente pode ser identificado em um morfismo degrafo C-tipado com outro arco de atributo que tenha o mesmo tipo no grafo declasses subjacente. Uma mensagem, contudo, pode ser identificada com qual-quer mensagem que a redefina. As razões para isso deverão ficar claras naSeção 8.4.

Morfismos de grafos C-tipados são mapeamentos que preservam as rela-ções de herança e sobrescrita entre os nodos e hiperarcos. Este fato vai aoencontro das características do paradigma, visto que a existência de um rela-cionamento de herança entre duas classes faz com que as funcionalidades daclasse primitiva estejam à disposição para todos os objetos de suas classesderivadas. Desta forma, pode-se considerar que um objeto não tem um tipoúnico, mas sim um conjunto de tipos, formado por todas as classes com asquais a classe de tipagem do objeto está relacionada via herança. Definir ummorfismo de grafos que leve em consideração a relação de herança garanteque o polimorfismo de subclasses possa ser aplicado de forma consistente.

Exemplo 8.3.4 (Morfismo de grafos C-tipados) A Figura 8.9 mostra um pos-sível morfismo entre os grafos C-tipados G1 e G2 (o morfismo h é representadopor linhas tracejadas), ambos tipados sobre o mesmo grafo de classes da Fi-gura 8.7. Note que os nodos dos grafos G1 e G2 possuem os mesmos nomesque os do grafo de classes. Na realidade, esses nomes indicam o morfismo detipagem, de maneira a tornar o morfismo em si mais claro e o visual do grafomenos poluído. No entanto, essa clareza deve ser entendida pelo que de fatoela é: uma representação do morfismo de tipagem pelos nomes dos elementospresentes nos grafos.

Como o objeto de tipo Drawing também é um objeto de tipo Figure, e comouma classe Circle também é uma classe Round este morfismo é permitido. Defato, pela definição temos que, além do mapeamento ter que ser um morfismode grafos (ou seja, origens e destinos dos arcos são preservados), para todov ∈ dom(hV), (t2V ◦ hV)(v) vVC

t1V(v), e para todos os elementos e∈ dom(hE),(t2E ◦hE)(e) vEC

t1E(e). De fato, assumindo que os nodos são numerados de

motivo de confusão para o leitor.

418

Page 33: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.9. Morfismo de grafos C-tipados

cima para baixo, temos que

(t2V ◦hV)(v1) = Drawing vVCFigure= t1V(v1)

(t2V ◦hV)(v2) = Circle vVCRound= t1V(v2)

(t2V ◦hV)(v3) = Color vVCColor = t1V(v3)

(t2V ◦hV)(v4) = Integer vVCInteger= t1V(v4)

(t2V ◦hV)(v5) = Integer vVCInteger= t1V(v5)

(t2E ◦hE)(1) = 1 vEC1 = t1E(1)

(t2E ◦hE)(2) = 2 vEC2 = t1E(2)

Como somente são representados arcos de atributos na figura, então ostipos devem ser estritamente preservados. No caso de haver mensagens, elasteriam que obedecer à relação de sobrescrita.

Para definirmos grafos orientados a objeto, contudo, precisamos prestaratenção no tipo de mensagem que cada objeto pode receber e quais são (equantos são) os atributos permitidos. Quando se define um sistema orientadoa objeto, espera-se que cada objeto criado carregue consigo uma estruturainterna que corresponda a todos os atributos de sua própria classe somadosa todos os atributos herdados das classes primitivas; da mesma forma, todosos métodos da classe juntamente com os herdados (e não redefinidos) devemestar disponíveis. Um grafo C-tipado contém todos os mapeamento adequa-dos para lidar com herança e sobrescrita de métodos. Contudo, não possuilimitação na quantidade de atributos que cada objeto pode ter e sobre mensa-gens que foram redefinidas estarem endereçadas a objetos que as redefiniram.Desta forma, para definirmos formalmente o que deve vir a ser um sistema ori-entado a objeto, devemos restringir a definição de grafo C-tipado de maneira aque nossos propósitos sejam alcançados.

419

Page 34: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Um grafo orientado a objeto será então um caso particular de um grafo C-tipado. Antes de apresentarmos a definição formal, contudo, algumas funçõesauxiliares serão definidas, conforme a Definição 8.3.6 apresentada a seguir.

Definição 8.3.6 (Conjuntos gerados de atributos e mensagens) Seja〈G, t,C〉 um grafo C-tipado onde G = 〈VG, EG, srcG, tarG〉 e C = 〈Vv, Ev, L, src,tar, lab〉. Sejam então definidas as seguintes funções:

• a função de conjunto de atributos attrG : VG →P(EG) retorna para cadavértice v∈VG o conjunto {e∈ EG | srcG(e) = v∧ lab(tE(e)) = attr}. Isto é,para cada vértice v de um grafo C-tipado esta função devolve o conjuntoque contém todos os arcos de atributos que têm como origem o nodo v;

• a função de conjunto de mensagens msgG : VG → P(EG) retorna paracada vértice v ∈ VG o conjunto {e∈ EG | tarG(e) = v∧ lab(tE(e)) = msg}.Isto é, para cada vértice v de um grafo C-tipado esta função devolve oconjunto que contém todas as mensagens endereçadas ao nodo v;

• a função de conjunto de atributos estendida, attr∗C : V → P(E), ondeattr∗C(v) = {e∈ E | lab(e) = attr∧ src(e) ∈ ↑v}. Isto é, para cada vérticev de um grafo de classes esta função devolve o conjunto que contémtodos os arcos de atributos que têm como origem o nodo v mais aquelesatributos que têm como origem as classes primitivas de v, ou seja, todosos atributos de uma determinada classe representada pelo vértice v;

• a função de conjunto de mensagens estendida, msg∗C : V →P(E), ondemsg∗C(v) = {e∈ E|msg | tar(e) ∈ ↑v∧¬∃e′ ∈ E|msg : tar(e′) ∈ ↑v∧ e′ vE e}.Isto é, para cada vértice v de um grafo de classes esta função devolve oconjunto que contém todas as mensagens (herdadas ou não) que podemser endereçadas a v, com exceção daquelas que foram redefinidas poralguma mensagem deste conjunto; ou seja, todas as mensagens quepodem ser enviadas à classe representada pelo vértice v.

Para qualquer grafo C-tipado 〈G, t,C〉 existe uma função total t∗E : P(EG)→P(EC), que pode ser vista como uma extensão da função de tipagem paraconjuntos de nodos ou de arcos. A função t∗E, quando aplicada a um conjuntoE ∈P(EG), retorna o conjunto {tE(e) ∈ EC | e∈ E} ∈P(EC). A notação t∗E|msge t∗E|attr será usada para indicar a aplicação de t∗E a conjuntos contendo exclu-sivamente arcos mensagens e atributos (respectivamente). Com as funções jádefinidas, pode-se então definir o tipo de grafo que vai representar sistemasorientados a objeto.

Definição 8.3.7 (Grafo orientado a objeto) Seja C um grafo de classes. Umgrafo C-tipado 〈G, t,C〉 é um grafo orientado a objeto se e somente se para todov∈VG tem-se que

1. (t∗E|msg◦msgG)(v) = (msg∗C ◦ tV)(v) e

2. (t∗E|attr◦attrG)(v) = (attr∗C ◦ tV)(v).

420

Page 35: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Se, para todo v ∈ VG a função t∗E|attr(attrG(v)) for injetora, GC é dito um grafoorientado a objeto estrito. Se t∗E|attr(attrG(v)) for também sobrejetora, GC échamado um grafo orientado a objeto completo.

Grafos orientados a objeto diferem dos grafos C-tipados no seguinte sen-tido: o único tipo de mensagem que pode ser recebida por um objeto são asmenores possíveis de acordo com a relação de sobrescrita. Isso porque, se-gundo a primeira condição apresentada na Definição 8.3.7, uma mensagemque tem como destino um objeto somente pode ser tipada por algum dos tiposretornados pela função de conjunto de mensagens estendida. Isso quer dizerque não é possível termos uma mensagem tipada como algum método que jáfoi redefinido. Isso é feito para garantir a implementação da ligação dinâmicade métodos, visto que um objeto sempre responde ao método mais próximo aele na hierarquia de herança e sobrescrita. A forma de garantir que isso sem-pre acontece será discutida na Seção 8.4, quando computações de sistemasorientados a objeto forem discutidas.

Grafos orientados a objeto podem ser estritos ou completos. Grafos orien-tados a objeto estritos são aqueles onde cada nodo não pode possuir dois oumais atributos tipados como o mesmo arco no grafo de classes subjacente. Ainjetividade de todas as funções t∗E|attr(attrG(v)), onde v∈VG, expressa que to-dos os arcos de atributo de um mesmo vértice são tipados de forma distinta (ouseja, um objeto não possui atributos em excesso). Para que um grafo orientadoa objeto seja completo, no entanto, também é necessário que todos os atribu-tos definidos em todos os níveis da relação de herança estejam presentes. Adefinição de um grafo orientado a objeto completo é coerente com a noção deherança no paradigma da orientação a objeto: um objeto possui todos os atri-butos definidos no âmbito de sua própria classe e herda todos os atributos, eexatamente os atributos, que pertencem às suas classes primitivas.

Sistemas orientados a objeto são usualmente compostos por um númerogrande de objetos, que podem receber mensagens de outros objetos (inclu-sive de si próprio) e reagir a estas mensagens alterando seu estado internoou enviando mensagens a outros objetos. Grafos orientados a objeto podemrepresentar um sistema orientado a objeto de forma adequada: eles podem terquantos objetos se desejar, e mesmo que o número e tipo de atributos em cadaobjeto seja limitado, o número de nodos no grafo que representa o sistema nãoé. Sendo assim, temos um formalismo capaz de expressar a estrutura estáticadas classes definidas em um programa orientado a objeto, juntamente com osestados de um programa em execução onde os nodos do grafo são os objetose os hiperarcos são todos os atributos e todas as mensagens a executar.

Para expressarmos a dinâmica da execução de um programa orientado aobjeto, contudo, precisamos de outro formalismo, capaz de expressar a ma-neira como os estados de um programa evoluem com o tempo. Para isso, naSeção 8.4 introduz-se formalmente o conceito de gramática de grafos orien-tados a objeto, que é capaz de expressar finitamente todas as computações(finitas ou infinitas) de um sistema orientado a objeto.

421

Page 36: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

8.4. Gramáticas de grafos orientados a objeto8.4.1. Regras e grafos

Sistemas baseados em regras já provaram ser bastante úteis para descre-ver computações por meio de transformações locais: regras aritméticas, sintá-ticas e de dedução são exemplos familiares. Definição sintática de linguagens,semântica de linguagens de programação, programação funcional, programa-ção em lógica, especificação algébrica, reescrita de termos, prova automáticade teoremas, sistemas especialistas, processos concorrentes e móveis são al-guns exemplos de áreas onde o papel das regras é de fundamental importân-cia.

Sistemas de transformação de grafos baseados em regras constituem umamaneira bastante natural de combinar grafos, para a descrição de estruturascomplexas, com regras, para manipular estas estruturas. Transformação degrafos, também conhecida como reescrita de grafos, combina os potenciais evantagens de ambos, grafos e regras, em um único paradigma computacional.

A teoria de sistemas de transformação de grafos estuda uma va-riedade de formalismos que expandem a teoria de linguagens for-mais [Hopcroft 1969], [Hopcroft et al. 2001], [Lewis and Papadimitriou 1998],[Martin 1996] para abarcar estruturas mais genéricas especificadas como gra-fos. Todas as construções conhecidas da teoria de linguagens formais baseadaem transformações de strings também existem em sistemas de transformaçãode grafos: regras, gramáticas, derivações e linguagens geradas por uma gra-mática podem ser definidas para grafos da mesma maneira que são definidaspara strings. Também da mesma forma, diferentes tipos de regras geram dife-rentes classes de linguagens, com expressividade diferentes e também diferen-ças na decidibilidade dos problemas associados. Já foi provado, contudo, quetodos os conjuntos enumeráveis de grafos podem ser gerados usando regrasde transformação de grafos bastante restritas [Nagl 1986].

Da mesma forma que gramáticas de strings, gramáticas de grafos (siste-mas de transformação de grafos equipados com um grafo inicial) também de-terminam um modelo de computação. A estrutura dos grafos usada, o tipo deprodução de grafos e o resultado da aplicação das regras determinam o modelode computação específico.

Um sistema de transformação de grafos permite que uma coleção (finita ouinfinita) de grafos seja descrita finitamente. Esta coleção é constituída de todosos grafos que podem ser obtidos a partir de um grafo inicial por meio da apli-cação repetida de regras (ou produções) de grafos. Uma produção de grafos,ou simplesmente uma regra, especifica como uma configuração de um sistemapode ser alterada. Uma regra tem um lado esquerdo e um lado direito, quesão ambos grafos orientados a objeto estritos (Definição 8.3.7), e um morfismoentre estes dois grafos, que determina o que deve ser alterado. Intuitivamente,uma alteração descrita por uma regra ocorre da seguinte maneira: todos oselementos que pertencem ao lado esquerdo da regra devem estar presentesno grafo que representa o estado do sistema para que a regra possa ser apli-

422

Page 37: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

cada; todos os itens mapeados do lado esquerdo da regra para o lado direitoda regra (via o morfismo entre os dois lados da regra) serão preservados pelaaplicação da regra; todos os elementos do lado esquerdo da regra que nãosão mapeados são removidos; e, finalmente, todos os elementos que apare-cem somente do lado direito da regra são adicionados ao estado corrente dosistema.

Exemplo 8.4.1 (Aplicação de regra) A Figura 8.10 apresenta um exemplo deaplicação de regra. A regra em questão é representada pelos dois grafos naparte superior da figura, onde r representa o morfismo entre eles. Os nodos earcos do grafo estão identificados pelos seus tipos, como de hábito, para queo morfismo de tipagem não precise ser indicado explicitamente. Todos os gra-fos são tipados sobre o grafo de classes apresentado na Figura 8.7. No ladoesquerdo da regra temos uma mensagem Draw enviada a um objeto de tipoFigure, que possui um atributo consists de tipo Round. De acordo com o mor-fismo r da regra, os objetos Figure e Round e o atributo consists devem serpreservados, já que se encontram tanto no grafo do lado esquerdo quando nodo lado direito da regra (isto é, são mapeados pelo morfismo r, embora estemapeamento não apareça explicitamente na figura). A mensagem Draw queaparece do lado esquerdo da regra deve ser removida na sua aplicação, vistoque não é mapeada para o lado direito. A mensagem Draw endereçada aoobjeto Round, que só aparece do lado direito, deve ser adicionada. Note quea mensagem Draw que aparece do lado esquerdo da regra não pode ser domesmo tipo que a mensagem Draw que aparece do lado direito: se houvesseeste mapeamento, a regra não seria um morfismo de hipergrafos (não preser-varia a origem e o destino dos elementos). A mensagem Draw que aparecedo lado direito é, de acordo com o grafo de classes que tipa os elementos,a mensagem Draw endereçada à classe Shape, que é herdada pela classeRound.

Na aplicação da regra, devemos achar uma ocorrência do grafo do seu ladoesquerdo no grafo ao qual a regra será aplicada (e que vai representar o estadoda execução do programa orientado a objeto). Uma ocorrência também é ummorfismo de grafos C-tipados, só que deve ser total — todos os elementos dolado esquerdo devem estar no grafo do sistema. A ocorrência é mostrada expli-citamente na figura, e o grafo resultante H é construído conforme a semânticade aplicação de uma regra descrita: o elemento que é a imagem da mensa-gem Draw do lado esquerdo é apagado do grafo, a nova mensagem Draw éadicionada na imagem de seu nodo de destino e todos os outros elementospermanecem como estão: tanto os que foram preservados pela regra como osque não foram mapeados pelo morfismo de ocorrência.

O tipo de regra permitida pode variar, de acordo com aquilo que se querrepresentar ou implementar. Regras sem qualquer tipo de restrição permitemuma expressividade muito grande na especificação de sistemas. Contudo, elastambém podem levar a muitos problemas indecidíveis. Restrições em regras

423

Page 38: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.10. Exemplo de aplicação de regra

são importantes não só para tornar problemas interessantes decidíveis (o quepor si só é importante) mas também para refletir restrições existentes nos sis-temas que estamos tentando modelar. Todas as restrições de regras apresen-tadas na Seção 8.4.2 dizem respeito aos princípios da programação orientadaa objeto.

8.4.2. Regras orientadas a objetoPara definir que tipo de regras de transformação de grafos serão permiti-

das para descrever as computações de um sistema orientado a objeto, deve-se levar em consideração as restrições e particularidades do paradigma. Deacordo com os princípios da orientação a objeto, um sistema é composto porum conjunto de objetos que se comunicam trocando mensagens (que em mui-tas linguagens são implementadas por invocações de métodos). Cada objetoresponde a uma mensagem recebida executando uma série de ações. Adici-onalmente, na execução dessas ações, um objeto somente tem acesso à suaprópria estrutura interna (oclusão da informação). Caso um objeto queira al-terar o estado interno de outro objeto, deve enviar uma mensagem (se estaestiver disponível) solicitando essa alteração.

Sendo assim, faz sentido que o lado esquerdo de uma regra (aquilo quedeve estar presente no sistema para que a regra possa ser aplicada) conte-nha exatamente uma mensagem a ser tratada, juntamente com o objeto quea recebe. Naturalmente que esta mensagem deve ser consumida pela apli-cação da regra (ou seja, o arco da mensagem não poderá ser mapeado pelomorfismo da regra). A exigência de somente existir uma mensagem do ladoesquerdo da regra não é uma restrição muito forte às possíveis computaçõesdo sistema, visto que muitas regras podem especificar reações ao mesmo tipode mensagem (não determinismo) e várias regras podem ser aplicadas em pa-

424

Page 39: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.11. Mudança da classe de um objeto devido àaplicação de uma regra

ralelo (concorrência), desde que não estejam em conflito [Ehrig et al. 1996a].Além disso, também devem estar presentes os atributos necessários para queas ações correspondentes à regra possam ser executadas.

Alguns cuidados adicionais precisam ser tomados em relação ao morfismoda regra. Em programas reais, um objeto nunca muda de tipo ao longo dacomputação4, mas as características de um morfismo entre grafos orientadosa objeto podem levar a que isso ocorra. O Exemplo 8.4.2 ilustra a situaçãoem que um objeto pode ter seu tipo (sua classe de definição) alterado por umaaplicação de regra.

Exemplo 8.4.2 (Mudança de classe de objeto) Considere a derivação des-crita na Figura 8.11. Os grafos deste exemplo também são tipados sobre ografo de classes apresentado na Figura 8.7, e o morfismo de tipagem é implí-cito pelo nome dos elementos.

O mapeamento da regra apresentado na Figura 8.11 é um morfismo de gra-fos C-tipados perfeitamente legal: uma classe Drawing também é uma classeFigure e um elemento da classe Circle também é um elemento da classeShape. O morfismo de ocorrência identifica os objetos do lado esquerdo daregra com elementos do grafo G que têm exatamente os mesmos tipos. G é ografo que representa o sistema orientado a objeto que está sendo transformadoe H é o grafo resultante da transformação. Note, contudo, que o objeto tipado

4 Linguagens de programação orientadas a objeto utilizam referências na forma de apon-tadores (às vezes chamados ponteiros) para objetos. Neste caso, mesmo que o tipo doobjeto referenciado possa mudar ao longo da computação, o tipo da referência em sinão muda.

425

Page 40: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

como uma Figure em G é mapeado (através do morfismo r ′, que é o espelho domorfismo r no grafo do sistema) para um objeto da classe Drawing; da mesmaforma, o objeto tipado como Shape é mapeado para um objeto tipado comoCircle.

O morfismo r ′ mantém o registro da evolução dos objetos à medida queo tempo passa. Os objetos mapeados por este morfismo correspondem aomesmo objeto em qualquer ponto de uma computação, o que quer dizer quese permitirmos regras onde um objeto troca sua classe, o mesmo pode ocorrerde fato durante uma computação do sistema. A maneira de impedir que issoaconteça é exigir que a função que mapeia os objetos seja invertível. Como afunção de mapeamento dos nodos em um morfismo de grafos C-tipados exigeque, para que um nodo tipado como x seja mapeado para um nodo tipado comoy necessariamente yvV x (ou seja, y é uma subclasse de x no grafo de classescorrespondente), então a única maneira da função ser invertível é que yvV x eque xvV y. Mas, como vV é uma relação de ordem parcial (Definição 8.2.7), eportanto antisimétrica, tem-se que necessariamente x = y, ou seja, ambos osobjetos precisam ter o mesmo tipo.

Outra questão importante é que dois objetos não podem ser “fundidos” aolongo da computação. Embora faça sentido criar e eliminar objetos durante aexecução de um programa, não faz sentido fundi-los. Aliás, como seria a fusãode dois objetos? Teriam atributos duplicados? No caso da não duplicaçãode atributos, como os novos valores dos atributos seriam computados? Pelomenos esta não é uma construção existente nas linguagens orientadas a objetomais conhecidas. A solução deste problema consiste em exigir a injetividade domorfismo da regra. Se a regra for injetora, dois objetos diferentes continuarãosendo diferentes depois da aplicação da regra.

Como as regras devem corresponder às características do paradigma, aoclusão de informação deve ser implementada. Isso significa que um objetonão pode ter acesso à estrutura interna de outro objeto quando computa. Paracaracterizar esta restrição de visibilidade, somente um objeto do lado esquerdoda regra pode possuir atributos, e este deve ser precisamente o objeto que estárecebendo a mensagem que deverá ser consumida. A existência de arcos deatributo em objetos que são, por exemplo, atributos do objeto que recebe amensagem, ou atributos de algum objeto passado como parâmetro da mensa-gem a ser tratada, significa que o método que está sendo implementado podeacessar (ler ou mesmo modificar) estes atributos. Impedindo a existência des-tes arcos de atributo do lado esquerdo da regra garante-se que as restriçõesde visibilidade são implementadas.

Por fim, embora não faça sentido a remoção de atributos de objetos, vistoque um atributo pertence à estrutura interna de um objeto, que não é modi-ficada em tempo de execução, é permitido que atributos sejam apagados naaplicação de uma regra. Esse aparente contra-senso é exigido pelo fato deque um morfismo de grafos exige que a origem e o destino dos arcos sejampreservados. Sendo assim, a única maneira de fazer um arco apontar para

426

Page 41: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

outro objeto (o que significa na prática alterar o valor do atributo em questão),é removendo-o e criando-o novamente com a mesma origem (o objeto ao qualpertence) e com outro(s) destino(s), que correspondem ao(s) seu(s) novo(s)valor(es). Os plurais da frase anterior dizem respeito ao fato de um atributotambém ser um hiperarco e, por esta razão, poder ter mais do que um objetode destino. Contudo, para evitar que um objeto perca — ou ganhe — atributosao longo da computação, para cada arco de atributo removido (ou seja, queaparece no lado esquerdo da regra mas não no seu lado direito) deve ser cri-ado um novo arco de atributo no lado direito da regra com exatamente o mesmotipo; da mesma forma, para cada arco de atributo não mapeado no lado direitoda regra deve existir um arco de atributo correspondente (do mesmo tipo) dolado esquerdo da regra que é removido na sua aplicação. Formalmente, deveexistir uma bijeção entre os arcos de atributo de ambos os lados da regra.

A definição formal de regra orientada a objeto é dada pela Definição 8.4.1.

Definição 8.4.1 (Regra orientada a objeto) Uma regra orientada a objeto r éum morfismo de grafo C-tipado r = 〈rV , rE〉 : LC → RC , onde LC = 〈L, tL,C〉 eRC = 〈R, tR,C〉 são grafos orientados a objeto estritos tipados sobre o grafo declasses C, e tal que as seguintes propriedades são verdadeiras:

• rV é injetora e invertível, rE é injetora,

• {e∈ EL | labC(tL(e)) = msg} é um conjunto unitário, cujo único elementoé denominado mensagem do lado esquerdo da regra e cujo objeto dedestino é chamado vértice de atributos,

• se {v∈VL | e∈ EL,srcL(e) = v, labC(tL(e)) = attr} 6= /0 então é um conjuntounitário, cujo único elemento é o vértice de atributos,

• cada regra implementa uma resposta a uma mensagem no mesmo nível(classe) em que a mensagem é definida, i.e., se l é a mensagem do ladoesquerdo da regra, então (tV ◦ tarL)(l) = (tarC ◦ tE)(l),

• a mensagem do lado esquerdo da regra não pertence ao domínio de r,i.e., se l é a mensagem do lado esquerdo da regra, então l /∈ dom(r) e

• para todo vértice v∈VL existe uma bijeção b : {e∈ EL | labC(tL(e)) = attr∧srcL(e) = v}↔ {e∈ER | labC(tR(e)) = attr∧srcR(e) = rV(v)}, tal que tR◦b=tL e tL ◦b−1 = tR.

A Definição 8.4.1 trata dos requisitos básicos que respondem às caracte-rísticas do paradigma. Contudo, outros tipos de regras podem ser construídas,dependendo do tipo de sistema que se quer implementar. Em particular, pode-se ter regras que não permitam nem a criação nem a eliminação de objetos,regras que permitam somente a criação ou regras que permitam tanto a criaçãoquanto a eliminação de objetos ao longo da computação.

Estas regras podem parecer estranhas a quem está acostumado a progra-mar com linguagens tradicionais, visto que em geral não há restrições destetipo, podendo-se criar e eliminar objetos à vontade. A questão aqui é qual o

427

Page 42: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

objetivo da especificação: se quisermos modelar a estrutura e execução de umsistema orientado a objeto, não há razão para limitar a criação ou a eliminaçãode objetos. Contudo, se o objetivo é verificar propriedades de um sistema apartir de sua especificação, então a criação de objetos impede que métodosde verificação sobre estruturas finitas sejam utilizados, enquanto que a criaçãoe eliminação tornam a maior parte das propriedades não decidíveis, e portantoimpossíveis de verificar.

Para ilustrar como regras deste tipo podem ser especificadas, as Defini-ções 8.4.2 e 8.4.3 apresentam as suas definições formais.

Definição 8.4.2 (Regra orientada a objeto restrita) Uma regra orientada aobjeto restrita ou regra orientada a objeto sem criação ou eliminação de ob-jetos r é uma regra orientada a objeto r = 〈rV , rE〉 : LC → RC onde rV é umafunção total e sobrejetora.

O fato de que o mapeamento entre os nodos do lado esquerdo e do ladodireito da regra precisar ser total e sobrejetor garante que não há possibilidadenem de remoção nem de criação de novos nodos (objetos) no grafo do sistemapor causa da aplicação da regra. Se a função é total, significa que todos osnodos do lado esquerdo são preservados pela aplicação, ou seja, não há eli-minação. Se a função for sobrejetora, significa que para todo vértice do ladodireito da regra existe um vértice do lado esquerdo que o mapeia através daregra. Outra forma de ver esta questão é que, como o morfismo da regra é, pordefinição, injetor, o fato da função de mapeamento dos nodos ser sobrejetoraindica que existe uma bijeção (correspondência um para um) entre os nodosdos dois lados da regra, que são todos preservados na sua aplicação.

Definição 8.4.3 (Regra orientada a objeto irrestrita) Uma regra orientada aobjeto irrestrita é uma regra orientada a objeto com criação de objetosr = 〈rV , rE〉 : LC → RC onde ou dom(rV) = VL ou então dom(rV) = VL\{vérticede atributos}.

Regras orientadas a objeto irrestritas permitem que objetos possam serapagados, visto que o domínio da função de mapeamento dos vértices do grafodiz que ou todos eles são mapeados, isto é, todos serão preservados na apli-cação da regra (dom(rV) = VL) ou então o vértice de atributos é o único nodoremovido (dom(rV) = VL\{vértice de atributos}). Note que este fato implica umprincípio da boa programação orientada a objeto, onde um objeto somentepode eliminar a si mesmo.

Diferentes tipos de regras permitidas em uma gramática dão vazão a com-putações com diferentes características. As definições restantes, contudo, sãoas mesmas independentemente do tipo de regra escolhida. Deste ponto emdiante, o termo “regra orientada a objeto” se refere a qualquer um dos tipos deregras das Definições 8.4.2 e 8.4.3.

428

Page 43: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

8.4.3. DerivaçõesUma derivação direta, ou passo de derivação, representa uma mudança no

estado de um programa em execução, e é obtida pela aplicação de uma regraao grafo que representa o estado do sistema.

Uma regra representa uma maneira possível de evolução de um sistemaorientado a objeto em qualquer ponto de sua execução. Para que uma regrapossa ser aplicada, contudo, seus pré-requisitos devem estar presentes. Opré-requisito de aplicação de uma regra é dado pelo seu lado esquerdo. Sem-pre que o lado esquerdo de uma regra existir em algum ponto do grafo querepresenta o sistema, esta regra pode ser aplicada sobre aquele ponto. Essaé a noção de transformação local que os sistemas baseados em regras im-plementam e que já foi discutida anteriormente. Note que uma mesma regrapode potencialmente vir a ser aplicada em vários pontos distintos do grafo dosistema, bastando para isso que seu lado esquerdo apareça em mais que umlugar do grafo ao mesmo tempo. Sendo assim, não há impedimentos para quevárias aplicações ocorram simultaneamente. Note como várias aplicações deregra simultâneas são equivalentes a vários comandos sendo executados aomesmo tempo. Ou seja, aplicações de regras são naturalmente atividades quedescrevem sistemas concorrentes.

Para que uma regra seja aplicada, então, é preciso encontrar uma ocorrên-cia do lado esquerdo da regra no grafo que representa o sistema. Encontraruma ocorrência significa achar um mapeamento total entre dois grafos, que éformalmente expresso por um morfismo de grafos.

Definição 8.4.4 (Ocorrência orientada a objeto) Dado um grafo orientado aobjeto estrito GC e uma regra orientada a objeto r : LC → RC , uma ocorrên-cia orientada a objeto entre LC e GC é um morfismo de grafos C-tipadosm= 〈mV ,mE〉 : LC → GC tal que mV é uma função total, mE é uma função to-tal injetora, e para quaisquer dois elementos a,b∈ L, se m(a) = m(b) então oua,b∈ dom(r) ou a,b /∈ dom(r).

O papel de uma ocorrência é detectar uma situação em que uma re-gra possa ser aplicada. Isso ocorre sempre que o lado esquerdo da re-gra estiver presente em algum ponto do grafo que representa o estado daexecução do programa. Esse “match” é obtido pelo que é denominadoisomorfismo de subgrafos, e que é, em geral, um problema NP-completo[Garey and Johnson 1999]. Contudo, pela própria estrutura das regras usa-das, basta inspecionar o grafo de sistema por arcos do tipo mensagem, jáque somente na presença deles é que uma regra orientada a objeto pode seraplicada. Desta forma, podemos reduzir um problema que no caso geral temcomplexidade exponencial para (no pior caso) um procedimento que pode serrealizado em tempo linear (proporcionalmente ao número de mensagens nografo). Não é o objetivo deste trabalho realizar análises de complexidade dosalgoritmos associados à implementação de gramáticas de grafos orientados

429

Page 44: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

a objeto, mas é interessante apontar que este é um problema que pode serresolvido de forma eficiente.

Note-se que, pela definição de ocorrência, dois vértices distintos podem seridentificados pelo morfismo. Essa identificação faz sentido, porque um objetopode ter uma referência a si próprio ou enviar a si mesmo como parâmetrode uma mensagem para outro objeto. No entanto, não faz sentido identificardois atributos diferentes como sendo o mesmo atributo ou duas mensagensdistintas como sendo a mesma mensagem, então a função componente domorfismo que mapeia arcos deve ser injetora.

O morfismo de ocorrência também exige que elementos que são preser-vados pela regra não possam ser identificados com elementos removidos porela. Esta restrição existe para impedir que efeitos colaterais indesejados ocor-ram quando a regra for aplicada. Neste caso, o efeito colateral relevante é aremoção de um elemento que deveria ser preservado.

Depois de encontrada uma ocorrência, a regra em questão pode ser apli-cada. A idéia por trás de uma aplicação de regra é construir um novo grafo deestado a partir do grafo atual. Quando existe uma ocorrência do lado esquerdode uma regra para o grafo que representa o estado atual do sistema, pode-sedividir este grafo da seguinte forma: os elementos que estão na imagem domorfismo de ocorrência e os que não estão. Estes últimos são ditos pertence-rem ao contexto da aplicação da regra (que é todo o grafo tirando os elementosque estão na imagem da ocorrência). Os elementos que estão no contexto daaplicação não são alterados pela aplicação da regra5; os elementos que per-tencem à imagem do morfismo são alterados da seguinte forma: todos os ítensmapeados tanto pela ocorrência quanto pela regra são preservados e levadospara o novo grafo; todos os elementos que pertencem à imagem da ocorrênciamas cujas origens não pertencem ao domínio da regra (isto é, não são ma-peados pela regra) são apagados e não aparecem no novo grafo; finalmente,todos os elementos que não pertencem à imagem do morfismo da regra sãoadicionados ao novo grafo, que representa então o novo estado do sistema.O Exemplo 8.4.1 mostrou um exemplo de aplicação de regra, antes que suadefinição formal fosse apresentada. É interessante tentar mapear o exemplona definição formal de derivação direta, para verificar se tanto a prática comoa teoria foram entendidas.

Definição 8.4.5 (Derivação direta orientada a objeto) Dados um grafo ori-entado a objeto completo GC = 〈G, tG,C〉, uma regra orientada a objeto r : LC →RC e uma ocorrência orientada a objeto m : LC →GC , uma derivação direta ori-entada a objeto, ou aplicação de regra orientada a objeto, pode ser computada

5 Existe uma possível exceção se a regra permitir a remoção de nodos. Neste caso,quando um nodo é apagado todos os seus arcos incidentes são removidos também,mesmo que eles façam parte do contexto de aplicação. Essa é uma característica daabordagem single-pushout, e não será explorada neste texto. Mais detalhes podem serencontrados em [Ehrig and Löwe 1993] e [Ehrig et al. 1996a].

430

Page 45: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

em dois passos:

1. Construir a derivação resultante da aplicação da regra r à ocorrênciam conforme definido em [Ehrig et al. 1996a] e exemplificado no Exem-plo 8.4.1, conseguindo um hipergrafo H e morfismos r ′ : G→ H e m′ :R→ H;

2. para obter o grafo resultante da derivação HC = 〈H, tH ,C〉, equipar o re-sultado do item anterior com o morfismo de tipagem para os seus nodose arcos dado abaixo:

• para todo v∈VH , tH(v) = u(

tG(r ′−1(v))∪ tR(m′−1(v)))

,

• para todo e∈ EH |attr, tH(e) = u(

tG(r ′−1(e))∪ tR(m′−1(e)))

,

• para todo e ∈ EH |msg, tH(e) = e′, onde e′ ∈ msg∗C(tH(tarH(e))) e

e′ v∗E u [tG(r ′−1(e))∪ tR(m′−1(e))].

A tupla 〈HC , r ′,m′〉 é o grafo orientado a objeto completo resultante da aplicaçãoda regra r à ocorrência m. Uma derivação direta do grafo GC para o grafo HC

sob a regra r e ocorrência m é denotado por GC r,m⇒ HC .

Uma derivação de uma regra sobre uma ocorrência provoca o colapso doselementos que são simultaneamente mapeados pela regra e pela ocorrência,enquanto copia o restante dos elementos provenientes do contexto e do ladodireito da regra. Até aqui, esta definição é idêntica à da abordagem algébricapara gramáticas de grafos. A diferença fundamental encontra-se na tipagemdos elementos do grafo resultante.

Na abordagem tradicional, que usa morfismo de grafos tipados, os tiposdevem ser preservados pelo morfismo. Na abordagem aqui apresentada, asrelações subjacentes é que devem ser preservadas. Isso quer dizer que ele-mentos de tipos diferentes podem ser mapeados pelo morfismo de ocorrência(o que, como já foi visto, implementa o polimorfismo de subclasses), entãotem-se que decidir qual o tipo do elemento em questão no grafo resultante.

Note que no grafo resultante de uma aplicação de regra sob uma determi-nada ocorrência, cada elementos (nodo ou arco) pertence a uma das seguintestrês situações distintas: (i) o elemento pertence à imagem da ocorrência e épreservado pela aplicação da regra; (ii) o elementos não pertence à imagemda ocorrência, e neste caso é dito pertencer ao contexto da aplicação da regra;(iii) o elemento foi criado pela aplicação da regra. Se o elemento vem do con-texto ou do lado direito da regra, então o seu tipo é meramente copiado, vistoque o elemento em questão não está na imagem nem da ocorrência nem daregra. Para os elementos preservados pela regra, o tipo resultante é o maiorlimitante inferior (Definição 8.2.12) com respeito à relação pertinente (herançaou sobrescrita) entre os tipos dos elementos que estão na imagem do morfismoe da regra sob o mesmo elemento no lado esquerdo desta e que são mape-ados pelos morfismos m′ e r ′ para o mesmo elementos do grafo resultante. A

431

Page 46: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.12. Exemplo de inexistência de tipagem correta

necessidade de que a função que mapeia os vértices em uma regra orientadaa objeto seja invertível assegura que o maior limitante inferior entre os tiposdas imagens dos elementos preservados pela regra sempre existe. Sem essarestrição, seria impossível assegurar a existência de uma estrutura resultante,como o Exemplo 8.4.3 ilustra.

Exemplo 8.4.3 (Inexistência de tipagem correta) Considere os quatro gra-fos orientados a objeto da Figura 8.12, tipados sobre o grafo de classes daFigura 8.7. Todos eles possuem uma estrutura idêntica, composta de dois no-dos e um arco de atributo. Como tem sido feito, os elementos são nomeadospelos seus tipos no grafo de classes subjacente, para facilitar a visualização.

O grafo localizado no canto superior esquerdo da figura possui um nodotipado como Figure, que consiste (consists) de um elemento de tipo Shape.O elemento tipado como Figure é mapeado para elementos de tipo Figure eDrawing pelos dois morfismos que existem para os grafos orientados a objetolocalizados, respectivamente, no canto inferior esquerdo e no canto superiordireito. O elemento da classe Shape é mapeado para um objeto da classeCircle no grafo do canto inferior esquerda e para um objeto da classe Ellipseno grafo do canto superior direito. Ambos os morfismos são perfeitamentelegais, visto que tanto Circle quanto Ellipse são classes derivadas de Shape.Mas não existe nenhuma classe que seja subclasse, ao mesmo tempo, deCircle e de Ellipse, o que significa que o maior limitante inferior destes doisnodos com respeito à relação de herança não existe. Isso faz todo sentido nocontexto da herança simples, onde duas classes que não estão relacionadaspor herança (como é o caso) não podem possuir classes derivadas comuns.Formalmente, essa noção é expressa pela própria definição de relação estrita(Definição 8.3.1), que faz com que a intersecção dos conjuntos inferiores de

432

Page 47: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

dois elementos distintos não relacionados (direta ou indiretamente) seja vazio.

As mensagens, no entanto, necessitam de um cuidado especial. Como ografo do lado esquerdo da regra LC contém uma única mensagem que deveobrigatoriamente ser removida pela aplicação da regra (Definição 8.4.1), umamensagem no grafo resultante da derivação HC só pode ter vindo do grafo GC

ou do grafo RC . Se a mensagem vem de GC , que é um grafo orientado a objeto,não há necessidade de alterarmos o tipo da mensagem, visto que ela deveestar corretamente tipada. Mas, se ela vem de RC , precisamos nos assegurarque o seu tipo seja correto, de forma a que HC seja um grafo orientado a objetocomo requerido.

A situação potencialmente problemática é ilustrada na Figura 8.13. A regrar, nesta figura, implementa uma situação comum: o resultado da execução deum método é a chamada a um outro método que pertence a um dos atributosdo objeto em questão. Na implementação deste método, um objeto da classeFigure é desenhado pelo envio de uma mensagem para a forma geométricaque a constitui (da classe Shape) para que ela se desenhe (e isso é boa pro-gramação orientada a objeto: é a forma geométrica que deve saber desenhara si própria, a figura só deve ter conhecimento das formas que a compõem).Mas no grafo do sistema existe uma figura que tem uma elipse como formageométrica constituinte, e é sobre esta figura que a regra será aplicada. Comoo método Draw é redefinido neste nível (na classe Ellipse), a mensagem re-sultante não pode ser a mensagem Draw da classe Shape, mas a mensagemDraw da classe Ellipse. Para conseguir este resultado, no processo de tipa-gem do grafo resultante tem-se que verificar qual é a imagem da mensagemque está no lado direito da regra, ver qual é a classe do objeto para o qual amensagem aponta no grafo resultante e daí encontrar o tipo certo, o que é feitopegando o tipo da única mensagem do conjunto de mensagens que o objetono grafo resultante pode receber. Este processo é realizado usando a fun-ção de conjunto de mensagens estendida sobre a classe do objeto que recebea mensagem no grafo resultante da derivação e que está relacionada com otipo de mensagem que aparece no lado direito da regra via relação de sobres-crita. Esta mensagem é necessariamente única: ou é ela própria (se não foiredefinida ou se não é aplicado polimorfismo na ocorrência) ou é a mensagemredefinida, já que o resultado da aplicação da função função de conjunto demensagens estendida (Definição 8.3.6) é o conjunto dos tipos de mensagensque um objeto pode receber, excluindo as mensagens que foram redefinidas.

Note que este processo é o equivalente à implementação de ligação di-nâmica de métodos em programas orientados a objeto. A ligação dinâmicaimplementada em linguagens que suportam polimorfismo de subclasses e so-brescrita de métodos é um método que permite que em tempo de execuçãoseja definida qual método será efetivamente chamado, dependendo do tipo deobjeto que uma referência contém. Esse mecanismo provê grande flexibilidadeno desenvolvimento de sistemas orientados a objeto, e está embutido, por de-finição, no formalismo aqui apresentado.

433

Page 48: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.13. Ligação dinâmica como tipagem de mensagens

Resumindo, se a mensagem do grafo resultante da derivação vem do grafode contexto GC , não há necessidade de mudança de tipo da mensagem. Se,no entanto, ela vem do lado direito da regra RC , ela deve ter seu tipo definidonão pelo objeto para o qual aponta em RC , mas de acordo com o objeto para oqual a sua imagem aponta no grafo HC , visto que este elemento pode ter umtipo diferente do indicado na regra, se polimorfismo de subclasses foi usado nomorfismo de ocorrência e se a mensagem do lado direito da regra foi redefinidapara este objeto. Neste caso, a classe a que o objeto efetivamente pertencepode ser qualquer elemento do conjunto inferior da classe indicada na regra.

Pode-se mostrar que uma derivação orientado a objeto direta está bemdefinida, e que a estrutura proposta na Definição 8.4.5 sempre pode ser cons-truída. Adicionalmente, o grafo HC = 〈H, tH ,C〉 resultante da derivação é umgrafo orientado a objeto completo. Estes resultados teóricos são importantes,para mostrar que o que está sendo proposto reflete com fidelidade o que deveacontecer. Não faremos as demonstrações destes fatos neste texto, mas o lei-tor interessado pode encontrar todos os resultados teóricos referentes a esteformalismo em [Ferreira 2005].

Os grafos usados para representar sistemas orientados a objeto e os tiposde regras que podem ser aplicados sobre eles determinam algumas proprie-dades das computações destes sistemas. Em particular, propriedades de fe-chamento são interessantes, visto que podem fornecer informações sobre osresultados das computações de sistemas. Pode-se mostrar que a classe dosgrafos orientados a objeto completos é fechada para as derivações com regrasorientadas a objeto que não permitem eliminação de objetos, embora não sejapara derivações que usam regras irrestritas. Isso porque, de acordo com a de-finição de derivação, se um nodo do grafo é removido, todos os arcos (atributos

434

Page 49: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

e mensagens) incidentes a ele são removidos também. Se existe um objetoque mantém uma referência para o objeto apagado, este arco de atributo vaisumir, ou seja, existe a possibilidade de efeitos colaterais na estrutura internados objetos causados pela aplicação de uma regra com eliminação. Esta situ-ação é conhecida como remoção em contextos indefinidos, e é muito comumem sistemas distribuídos. Um exemplo muito familiar são os links de páginasna Internet. Se uma página referencia outra, que é removida ou muda de lugar,tem-se o que se chama de link quebrado, ou referência perdida. Na execuçãode um programa, qualquer computação com um objeto cuja referência foi per-dida vai causar um erro de execução. Essa situação pode ser detectada nomodelo definido com gramática de grafos orientados a objeto, caso as regraspermitam a eliminação de objetos.

A seguir, define-se formalmente o que é uma gramática de grafos orienta-dos a objeto.

Definição 8.4.6 (Gramática de grafos orientados a objeto) Uma gramáticade grafos orientados a objeto é uma tupla 〈IC ,PC ,C〉 onde IC é um grafo orien-tado a objeto completo, PC é um conjunto finito de regras orientadas a objeto eC é um grafo de classes.

O grafo inicial IC corresponde à configuração inicial do sistema orientado aobjeto que estamos modelando/programando. Neste grafo temos todos os ob-jetos presentes no sistema, com os valores de seus atributos (que são outrosobjetos) já definidos e com as mensagens que os objetos recebem inicialmente.Este grafo inicial vai evoluir ao longo do tempo por meio da aplicação das re-gras da gramática. O tipo de regra (se permite ou não criação e eliminação deobjetos) vai depender do problema que está sendo resolvido, conforme discus-são realizada anteriormente. Todos os grafos nesta definição (o grafo inicial eos lados esquerdo e direito de todas as regras) são tipados sobre o mesmografo de classes C.

Uma questão importante, que deve ser levantada quando se pretende mo-delar a solução de qualquer problema em alguma linguagem formal, seja estalinguagem mais abstrata como é o caso de gramáticas de grafos ou concretacomo uma linguagem de programação, é a questão da sua semântica. Lingua-gens de programação em geral vêm equipadas com uma semântica formal queexplica o significado (funcionamento) de cada uma das construções sintáticasda linguagem. No caso das gramáticas de grafos, diversas semânticas podemser construídas. Estas semânticas variam no aspectos que dizem respeito àconcorrência verdadeira (regras podem ser aplicadas ao mesmo tempo) ou in-tercalação de eventos. A diferença entre as duas consiste na mesma diferençaentre sistemas multiprocessados e multiprogramados: no primeiros temos maisdo que um processador executando, de fato, ao mesmo tempo; nos segundostemos um único processador compartilhado pelos processos que nele execu-tam. As semânticas podem ainda variar na quantidade de informação quelevam em consideração. Apesar da discussão sobre semânticas de gramáticas

435

Page 50: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

de grafos encontrar-se além do escopo deste trabalho, a programação serádaqui para a frente realizada supondo uma semântica de intercalação. Estasemântica é assumida porque os verificadores de modelos [Clarke et al. 1999],[Holzmann 1997], [Huth and Ryan 2000] que podem ser usados para verificarpropriedades específicas sobre os sistemas modelados usam esta semânticana geração do espaço de estados do problema, então faz mais sentido su-por que as gramáticas funcionem da mesma forma. Na prática, continua-sea manter os aspectos não determinísticos da execução (não existe seqüênciapré-determinada na execução de duas regras para as quais existe ocorrênciano grafo) mas a aplicação das regras não pode ser realizada de forma simultâ-nea.

Na Seção 8.5 serão apresentadas duas propostas de solução para um pro-blema clássico de concorrência, que são modeladas usando gramáticas degrafos orientados a objeto.

8.5. Programação com grafos8.5.1. O Jantar dos Filósofos (com bloqueio )

O problema do “jantar dos filósofos” foi originalmente apresentado por Eds-ger Dijkstra em 1965 [Dijkstra 1965], como forma de ilustrar uma situação inde-sejável que pode ocorrer em programas concorrentes. O problema consiste naseguinte situação: um número n de filósofos está sentado à volta de uma mesacircular com um prato de espaguete à frente, um garfo do seu lado esquerdo eoutro garfo do seu lado direito (isto é, existem n filósofos, n pratos e n garfos).A vida de um filósofo consiste em comer e pensar, em intervalos alternados detempo. Quando um filósofo pára de pensar, ele deve pegar ambos os garfos aoseu lado para que possa começar a comer. Como cada garfo é compartilhadoentre dois filósofos, filósofos adjacentes não podem comer ao mesmo tempo.A solução do problema envolve um programa em que todos os filósofos defato alternem sua vida entre períodos nos quais pensam e períodos nos quaiscomem. Para que isso ocorra, o programa deve apresentar a propriedade deque sempre que um filósofo decide começar a comer, ele consegue começar acomer em algum ponto do futuro. Se o programa apresenta esta propriedade,então não haverá situações indesejáveis, como as que são exemplificadas aseguir.

Uma abordagem intuitiva para resolver esse problema é fazer com que cadafilósofo pegue o garfo que está à sua esquerda, seguido do garfo que está àsua direita. Contudo, este algoritmo pode levar a uma situação de bloqueio(deadlock) uma vez que todas as quatro condições para a existência de blo-queios existem nessa situação: bloqueio de recursos compartilhados (garfos),ausência de preempção (nenhum filósofo pode pedir ao colega do lado paraceder o seu garfo), manutenção de recursos enquanto novos recursos são ad-quiridos (um filósofo fica segurando seu garfo esquerdo enquanto tenta pegaro garfo à sua direita) e espera circular (cada dois filósofos compartilham umgarfo) [Tanenbaum and Woodhull 1997].

436

Page 51: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

A solução deste problema consiste no desenvolvimento de um algoritmoque evite, ao mesmo tempo, bloqueios e postergações indefinidas (starvation).Inicialmente apresentaremos uma modelagem mais simples, mas que permiteo aparecimento de bloqueios. Essa modelagem é baseada na abordagem in-tuitiva para a solução apresentada anteriormente. A seguir é apresentada umasolução que não permite bloqueios, mas que pode apresentar postergaçõesindefinidas. A proposição de uma solução usando semáforos, que segue alinha da solução apresentada em [Tanenbaum and Woodhull 1997], será dei-xada como exercício para o leitor.

Pode ocorrer uma situação de bloqueio se todos os n filósofos conseguirempegar um dos garfos. Nessa situação, nenhum filósofo será capaz de pegar umsegundo garfo, visto que todos os n garfos estarão em poder de algum dos fi-lósofos. Assim, o primeiro filósofo espera que o segundo filósofo libere o garfo,que por sua vez espera que o terceiro filósofo libere o garfo, e assim suces-sivamente até que o círculo se feche. Se nenhum filósofo desistir de esperare largar o garfo, temos uma situação de bloqueio estabelecida e nenhum dosfilósofos pode prosseguir sua execução.

A falta de garfos disponíveis é uma analogia à alocação de recursos com-partilhados em uma situação de programação real. Alocar um recurso é umatécnica comum de programação, para garantir que nenhum recurso (impresso-ras, discos, arquivos, etc.) seja acessado por mais do que um programa outrecho de código simultaneamente. Quando um recurso de interesse estiveralocado, o programa deve esperar até que o recurso seja liberado. Quandomúltiplos programas estão alocando os mesmos recursos, situações de blo-queio e postergação indefinida podem ocorrer.

A primeira “solução” apresentada a seguir visa introduzir a modelagem ori-entada a objetos com gramáticas de grafos. A seguir, faz-se uma modelagemmais elaborada que efetivamente resolve o problema com respeito aos blo-queios. A prova de que a modelagem está de fato correta (i.e., apresenta aspropriedades de ausência de bloqueio e postergação indefinida) encontra-sealém do escopo deste texto. Contudo, faz-se uma discussão sobre como uti-lizar métodos de verificação formal em especificações usando gramática degrafos orientados a objeto. Inicialmente, deve-se construir o grafo de classespara o sistema, apresentado na Figura 8.14. Os nodos do grafo representam osobjetos que podem estar presentes no sistema, e que são os seguintes: Philo-sopher, que representam as entidades (programas) que alocam recursos; Fork,que representa os recursos compartilhados pelos filósofos; Table, que modelatanto o local onde os filósofos estão sentados como o local de onde os recur-sos (garfos) serão alocados; e ForkHolder, que pode ser tanto um Philosopherquanto um Table.

Os atributos existentes no grafo de classes contém a informação que os ele-mentos necessitam para computar corretamente: um Philosopher está (arcodenominado isAt) sentado em uma mesa (Table), possui um garfo (Fork ) lo-calizado à sua esquerda e outro à sua direita (atributos leftFork e rightFork,

437

Page 52: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.14. Grafo de classes para o problema do Jantardos Filósofos

respectivamente) que ele deve apanhar para poder comer. Note que um filó-sofo não pode pegar qualquer garfo da mesa, somente os que estão próximosa ele; um garfo (classe Fork ) tem um dono, que pertence à classe ForkHoldere, pela relação de herança, à classe Table ou à classe Philosopher. Comotodos os hiperarcos do grafo possuem somente um nodo de origem e um dedestino, eles serão representados como arcos comuns. O quadrado preto danotação utilizada até agora será descartado para facilitar a leitura.

As mensagens que aparecem na Figura 8.14 correspondem às ações queos objetos podem receber durante a execução do programa. Um Fork pode seradquirido por um Philosopher, e liberado por um Philosopher para uma Table(mensagens acquire e release, respectivamente). Um Philosopher pode estarpensando (thinking), comendo (eating), receber a mensagem eat, que faz comque ele comece a tentar comer, pegando os garfos de que precisa pra isso, oureceber a mensagem got, que o notifica que um Fork foi apreendido.

Notação: Os lados direito e esquerdo de regras orientadas a objeto são grafosorientados a objeto, isto é, grafos tipados sobre um grafo de classes (veja aSeção 8.3.2). No entando, de maneira a fazer esta apresentação mais clara,todos os arcos e nodos destes grafos são nomeados de acordo com o seu tipono grafo de classes, tornando o morfismo de tipagem explícito.

A Figura 8.15 apresenta as regras para a classe Fork. O lado esquerdo daregra AcquireFork possui, como esperado, uma única mensagem acquireendereçada a um nodo de tipo Fork e que tem um objeto da classe Philo-sopher como parâmetro. Note que esta regra somente poderá ser aplicadacaso o dono do garfo (o destino do atributo owner ) seja um objeto de tipo Ta-ble: neste caso, e somente neste caso, o dono do objeto da classe Fork passaa ser o objeto da classe Philosopher passado como parâmetro da mensagem,

438

Page 53: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.15. Regras para a classe Fork

o qual é notificado de que conseguiu apanhar o garfo em questão pela men-sagem got (na qual o garfo apreendido é passado como parâmetro). Um garfoé liberado (pela mensagem release) pela aplicação da regra ReleaseFork :um objeto de tipo Fork recebe uma mensagem de seu dono atual (um Philo-sopher ), indicando o objeto de tipo Table ao qual o grafo irá agora pertencer,então o Fork simplesmente muda o valor do atributo owner do Philosopherpara a Table.

A Figura 8.16 apresenta as regras da classe Philosopher. As regras im-plementadas para as mensagens eating e thinking existem para assegurar quepode haver um intervalo de tempo não determinado para os períodos em queo filósofo pensa e come. De acordo com a semântica usual das gramáticasde grafos, não existe ordem específica de aplicações de regras para as quaisexiste uma ocorrência. Também não existe restrição referente ao tempo decor-rido entre o aparecimento de uma mensagem e seu consumo. Uma ocorrênciapreviamente existente de uma regra para o grafo que representa o sistem podeinclusive deixar de existir antes que a regra seja aplicada, fazendo com quea aplicação em questão não seja mais possível. Sendo assim, o tempo queum filósofo passa comendo ou pensando depende somente do tempo passadoentre o recebimento da mensagem (eating ou thinking, respectivamente) e oseu consumo.

A aplicação da regra StopEating interrompe a atividade de comer do filó-sofo: um filósofo sentado à mesa que possui dois garfos envia uma mensagempara seus garfos direito e esquerdo, enviando a mesa na qual está sentado ea si mesmo como parâmetros. A aplicação da regra StopThinking consomea mensagem existente thinking, e interrompe a atividade de pensar enviandouma mensagem para o filósofo que estava pensando (e que possuía a mensa-

439

Page 54: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.16. Regras para a classe Philosopher

gem) dizendo que é hora de comer (mensagem eat).Um Philosopher responde à mensagem eat tentando apanhar o garfo que

está à sua esquerda. Este processo é modelado pelo envio da mensagemacquire ao atributo tipado como leftFork. Uma vez que o filósofo receba amensagem got deste atributo, ele começa a tentar apanhar o garfo à sua direita,enviando a mensagem acquire ao garfo à sua direita (o atributo tipado comorightFork ). Quando uma mensagem got é recebida deste atributo, o filósofopode começar então a comer, o que é indicado pelo envio da mensagem eatinga si mesmo, sinalizando que o período de comer teve início.

A Figura 8.17 mostra o grafo inicial para o problema do Jantar dos Filósofos.Conforme se pode ver, tem-se cinco filósofos — Sócrates, Platão, Nietzsche,Hegel e Kant — sentados em uma mesa, tendo um garfo entre cada dois deles.Inicialmente, todos os filósofos estão pensando, conforme indicado pelas men-sagens direcionadas a cada um deles. O processo de pensar de cada um podeser interrompido a qualquer momento, pela aplicação da regra StopThinking(Figura 8.16), que somente requer a existência de uma mensagem thinking en-

440

Page 55: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.17. Grafo inicial para o problema do Jantar dos Filósofos

dereçada a um filósofo para ser aplicada. Note que existem cinco ocorrênciaspossíveis desta regra no grafo inicial.

É fácil construir uma computação que leve a uma situação de bloqueio:basta que uma regra StopThinking (Figura 8.16) seja aplicada em cada umdos cinco filósofos ao redor da mesa. Neste caso, todos eles estariam re-cebendo a mensagem eat. Se a todos os filósofos for aplicada então a regra1stFork (Figura 8.16), será enviada uma mensagem acquire a todos os garfosda mesa (que correspondem exatamente aos garfos do lado esquerdo de cadafilósofo). Como todos os garfos estão inicialmente sobre a mesa, existe umaocorrência para a aplicação da regra AcquireFork (Figura 8.15) em todas asmensagens geradas. Todos os garfos terão agora um filósofo como dono, e to-dos os filósofos serão notificados com a mensagem got, gerada pela aplicaçãoda regra anterior. Todos os filósofos tentarão conseguir um segundo garfo paracomeçar a comer, a regra 2ndFork pode ser aplicada a todos eles, enviandoagora uma mensagem acquire aos garfos do lado direito dos filósofos. A partirdaí, nenhuma outra computação é possível. Todos os garfos estão alocadospara algum filósofo, que não devolve o garfo à mesa enquanto não conseguircomer. Não há maneira das mensagens acquire poderem ser consumidas, euma situação de bloqueio está estabelecida.

Note que esta computação específica leva a uma situação de bloqueio em-bora muitas outras possam não levar. Sendo assim, esse modelo não é correto,pois a propriedade de que sempre que um filósofo desejar comer ele o conse-guirá no futuro não é verdadeira.

441

Page 56: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

8.5.2. O Jantar dos Filósofos ( sem bloqueio )A solução proposta em [Tanenbaum 1992] para o problema do Jantar dos

Filósofos utiliza semáforos para organizar o jantar de modo que todo filósofoque decida comer atinja seu objetivo após um intervalo finito de tempo. A abor-dagem realizada aqui é inspirada naquela, mas difere em alguns conceitosfundamentais: em primeiro lugar, uma regra é aplicada na sua totalidade, ouseja, não existem estados intermediários em sua aplicação. Por outro lado, nãosão definidas primitivas de bloqueio ou de sincronização de processos, entãoestas construções precisam ser definidas nas regras de gramática. A soluçãoapresentada aqui inspira-se na solução proposta por Dijkstra no seguinte sen-tido: um filósofo F somente consegue apanhar seu primeiro garfo (o esquerdo),se o filósofo à sua esquerda FE ainda não iniciou o seu processo de começar acomer. No caso do filósofo à esquerda FE já ter iniciado seu processo de inícioda refeição, então ele já deve ser detentor do seu garfo à esquerda. Se o garfoque o primeiro filósofo F está tentando buscar for adquirido, o filósofo FE ficarábloqueado. Se esse processo se repetir (como foi o caso no exemplo da seçãoanterior), então pode haver uma situação de bloqueio.

A alteração do algoritmo será realizada nos seguintes termos: antes deum filósofo conseguir adquirir um garfo, será verificado se o primeiro garfo dofilósofo à esquerda já foi adquirido; em caso negativo, o filósofo consegue ad-quirir o garfo; em caso positivo, o filósofo não consegue adquirir o garfo e oprocesso de aquisição recomeça. Para conseguir realizar este processo, cadagarfo precisa saber qual é o garfo que deve estar liberado para que o pro-cesso de aquisição possa ser completado. Isso é feito via uma modificaçãono grafo de classes do sistema, onde a classe Fork terá um atributo a mais(refFork ), que vai apontar para este elemento. Outras modificações tambémsão necessárias no grafo de classes. Em particular, esta troca de informaçõesentre garfos precisa ser feita por troca de mensagens. As novas mensagensda classe Fork são as seguintes: acqFirst, free?, ok, nok. O novo grafo declasses para esta solução do problema do Jantar dos Filósofos é apresentadona Figura 8.18.

A mensagem acqFirst é a mensagem enviada por um filósofo para o seugarfo à esquerda quando deseja começar a comer. É necessário agora dife-renciar a mensagem de aquisição do primeiro garfo, porque os processos sãodiferentes: é necessário verificar se o garfo à esquerda do filósofo à esquerdade quem faz a requisição está ou não alocado, o que não é feito na aquisiçãodo segundo garfo. Esta requisição é feita pela mensagem free? que é enviadaao garfo pertinente. As mensagens ok e nok são enviadas pelo garfo que rece-beu a requisição respondendo, respectivamente, que o garfo em questão estálivre ou alocado. As novas regras para a classe Fork estão representadas naFigura 8.19.

As novas regras da classe Fork são denominadas Acquire1stFork ,ForkFree , ForkOwned , FirstForkAcq e FirstForkAgain . As regrasAcquireFork e ReleaseFork são idênticas àquelas apresentadas para esta

442

Page 57: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.18. Grafo de classes para o problema do Jantardos Filósofos (sem bloqueio)

classe na seção anterior. As modificações dizem respeito basicamente às alte-rações no algoritmo. A regra Acquire1stFork inicia os procedimentos paraque um garfo possa ser liberado para um filósofo, que é passado como parâ-metro da mensagem acqFirst, implementada nesta regra. Note que somenteexiste uma ocorrência para aplicação desta regra se o garfo em questão es-tiver sobre a mesa (isto é, não alocado a nenhum filósofo). Se a ocorrênciaexistir, o objeto de tipo Fork que recebe a mensagem procede às seguintesações: em primeiro lugar, passa a pertencer ao filósofo que gerou a men-sagem (passado como parâmetro desta), para evitar que outro filósofo possase apossar deste garfo enquanto o procedimento é realizado; depois, enviauma mensagem free? ao garfo esquerdo do filósofo do lado esquerdo (queestá referenciado pelo atributo refFork de cada garfo), passando a si mesmoe o objeto Table ao qual pertencia como parâmetro. As regras ForkFree eForkOwned implementam a mesma mensagem free?. A aplicação destas re-gras no mesmo objeto, contudo, é excludente, visto que jamais pode haver umaocorrência para as duas regras simultaneamente. A regra ForkFree pode seraplicada quando o objeto de tipo Fork ao qual ela se destina encontra-se so-bre a mesa (não está alocado a nenhum filósofo); neste caso, o objeto Forkcontinua pertencendo à mesa (seu estado não é alterado pela aplicação daregra) e é enviada uma mensagem ok ao garfo inquiridor, que veio como pa-râmetro da mensagem. Caso o garfo inquirido pertencer a um filósofo, entãoexiste uma ocorrência para a regra ForkOwned . Neste caso, o objeto inquiridotambém não tem seu estado alterado, mas envia uma mensagem nok para o

443

Page 58: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

Figura 8.19. Regras para a classe Fork (sem bloqueio)

444

Page 59: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.20. Regra adicional para a classe Philosopher(sem bloqueio)

objeto que fez a pergunta (passado como parâmetro da mensagem free?), si-nalizando que ele não está livre. Quando um garfo recebe a mensagem ok, aregra FirstForkAcq sempre pode ser aplicada (note que a ocorrência sem-pre vai existir, visto que o garfo já foi alocado para um filósofo) e a única ação énotificar o filósofo que pediu o garfo e que ainda não tinha sido notificado sobreisso. Se a mensagem recebida for nok, contudo, tempos uma possível situaçãode bloqueio no horizonte. Neste caso, a regra FirstForkAgain é aplicada, oobjeto Fork volta a pertencer à mesa, e a mensagem que deu origem a todoo processo, acqFirst é enviada novamente ao garfo, com os parâmetros ori-ginais, reiniciando o processo. A única alteração que é necessária fazer nasregras da classe Philosopher (apresentadas originalmente na Figura 8.16) éna regra PhilFirstFork , que ao invés de enviar a mensagem acquire agoradeve enviar a mensagem acqFirst, que dá conta da verificação do estado dogarfo esquerdo do filósofo da esquerda do que está enviando a mensagem. Aregra alterada para a classe Philosopher está descrita na Figura 8.20.

O grafo inicial do problema também é alterado, de maneira que cada garfoconheça o garfo que deve ser investigado. O esquema inicial da gramáticadefinida nesta seção é apresentado na Figura 8.21.

Note que esta solução não bloqueia o filósofo, que continua sempre ten-tando pegar o garfo. Esta solução apresentada, apesar de tornar impossívela existência de bloqueios, permite postergações indefinidas. Seja a seguintesituação (de acordo com o grafo inicial apresentado na Figura 8.21): a men-sagem thinking inicialmente enviada ao filósofo Hegel é consumida pela apli-cação da regra StopThinking , que envia uma mensagem eat para o mesmofilósofo. Esta mensagem é consumida então pela nova regra Phil1stFork(Figura 8.20), que produz a mensagem acqFirst que é enviada ao garfo dolado esquerdo de Hegel, Fork3. Como o atributo owner de Fork3 tem comotipo Table, a regra Acquire1stFork pode ser aplicada. Com a aplicaçãodesta regra, o atributo owner de Fork3 passa a apontar para Hegel e é en-viada uma mensagem free? ao garfo Fork4. Como Fork4 tem seu o atri-buto owner apontando para um objeto de tipo Table, existe uma ocorrênciapara a regra ForkFree e esta pode então ser aplicada. A aplicação da regraForkFree sobre o garfo Fork4 envia uma mensagem ok para o garfo Fork3que foi passado como parâmetro da mensagem free?. Neste momento, a re-

445

Page 60: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

gra FirstForkAcq é aplicada e o filósofo Hegel recebe a informação de queadquiriu o garfo Fork3. Neste momento, imagine que o filósofo Nietzsche temsua mensagem thinking consumida pela regra StopThinking . A mensagemeat enviada ao filósofo pela aplicação da regra também é consumida pela apli-cação da regra Phil1stFork , que envia uma mensagem acqFirst ao garfoFork2 que está à esquerda de Nietzsche. Como Fork2 pertence a uma Ta-ble a regra Acquire1stFork é aplicada e a mensagem free? é enviada aogarfo Fork3. Como Fork3 pertence agora a um filósofo (Hegel, no caso) so-mente existe uma ocorrência para a regra ForkOwned e é enviada então umamensagem nok para o garfo Fork2, que por sua vez, pela aplicação da regraFirstForkAgain reenvia a mensagem acqFirst tendo parâmetro o filósofoNietzsche. Recebendo essa mensagem do garfo à sua esquerda, existe umaocorrência para a regra 2ndFork e uma mensagem acquire é enviada agorapara o garfo à direita de Hegel, Fork2. Como Fork2 pertence à uma Table,a regra AcquireFork é aplicada, Hegel recebe uma mensagem got tendoFork2 como parâmetro. A regra StartEating pode então ser aplicada e He-gel começa a comer. Neste momento, a mensagem eating enviada a Hegelé consumida pela aplicação da regra StopEating , que pede a liberação deseus dois garfos para a mesa pelo envio da mensagem release para os garfosFork2 e Fork3 e da mensagem thinking para o próprio Hegel. Nesta situação,a mensagem acqFirst enviada a Nietzsche já poderia ser consumida pela apli-cação da regra AcquireFirstFork , que perguntaria ao garfo Fork3 se eleestava livre, o que resultaria em sucesso visto que o filósofo Hegel já haviaparado de comer. Contudo, imagine que o filósofo Hegel inicia novamente oseu processo de refeição antes que a seqüência de aplicação de mensagensdo garfo Fork2, requisitado por Nietzsche seja completada. Neste caso, Hegelcomeçaria a comer novamente e Nietzsche teria novamente que esperar. Umaseqüência possível de execução repete este ciclo permanentemente, e o filó-sofo Nietzsche jamais conseguirá adquirir o objeto Fork2 e assim começar acomer.

O desenvolvimento de uma solução que não permita bloqueios nem pos-tergações indefinidas, no estilo dos semáforos de Dijkstra, é deixado comoexercício para o leitor.

8.6. ConclusõesGramáticas de grafos orientados a objeto representam um formalismo para

especificação de modelos de sistemas ou programas orientados a objeto. O for-malismo em questão consiste em uma extensão da abordagem single-pushoutpara gramáticas de grafos com vistas a incorporar as principais característicasdo paradigma de orientação a objeto, nomeadamente: herança, polimorfismo,encapsulamento e oclusão da informação.

Hipergrafos rotulados denominados grafos de classes são as estruturasusadas para representar a hierarquia de classes em um sistema orientado aobjeto. Nodos representam classes, hiperarcos representam mensagens (mé-

446

Page 61: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

Figura 8.21. Grafo inicial para o problema do Jantar dosFilósofos (sem bloqueio)

todos) ou atributos. Adicionalmente, existe uma relação de ordem parcial res-trita sobre o nodos, que representa a herança entre classes, e sobre os arcosde mensagens, que representa a sobrescrita de métodos. Estas estruturasservem para tipar os grafos que representarão sistemas e regras de grafos.

Grafos tipados são comumente usados para garantir que um sistema obe-dece a uma certa estrutura permitida. Neste caso, o morfismo de tipagem(feito sobre um grafo de classes) serve para identificar a que classe um objetopertence, e quais são os atributos e mensagens existentes. Em orientação aobjetos, contudo, o mecanismo de herança permite que um objeto use atributosque suas classes primitivas têm, bem como execute métodos que estão decla-rados em outros níveis. O morfismo de tipagem aqui apresentado permite queum objeto faça uso de elementos herdados, como em um sistema orientado aobjetos tradicionalmente implementado com linguagens de programação textu-ais.

Morfismos de grafos orientados a objeto igualmente respeitam as relaçõesde herança e sobrescrita ao grafo de classe subjacente. Um elemento de umgrafo (nodo ou arco) pode ser mapeado para um outro elemento desde que am-bos os tipos estejam relacionados na relação pertinente. O encapsulamento dedados e funções na mesma entidade sintática é obtido por restrições estrutu-rais no grafo de classes.

Grafos de classes e grafos orientados a objeto representam a especifica-ção estática de um sistema. Para modelarmos o seu comportamento dinâmico(i.e., suas computações) gramáticas de grafos orientados a objeto são intro-duzidas. O tipo de regra permitido nas gramáticas utilizadas diz respeito àsrestrições impostas pelo paradigma. Um objeto somente age em função do

447

Page 62: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

recebimento de uma mensagem, e a aplicação de um método somente podefazer uso dos atributos (estado interno) do próprio objeto, garantindo que oprincípio de oclusão da informação seja respeitado. Sendo assim, cada re-gra representa a aplicação de um único método, embora possam existir váriasregras que implementem o mesmo método.

Os morfismos de ocorrência em gramáticas de grafos orientados a objetosão definidos da mesma forma que em gramáticas de grafos usuais: como ummorfismo total do lado esquerdo de uma regra para o grafo que representa oestado atual do sistema. Isso significa que o lado esquerdo de uma regra éum subgrafo do estado atual e a regra pode ser aplicada. Contudo, devido àscaracterísticas dos morfismos de grafos orientados a objeto, uma ocorrênciaimplementa também a noção de polimorfismo de subclasses, ou seja, todas asregras definidas para uma determinada classe podem ser aplicadas em objetospertencentes a qualquer uma de suas subclasses.

Uma derivação representa um passo de avanço na computação do sistema.A construção resultante implementa ainda a ligação dinâmica de métodos, tor-nando essa construção clássica da orientação a objeto uma característica ine-rente ao formalismo apresentado.

Gramáticas de grafos orientados a objeto representam um passo impor-tante na definição de linguagens visuais de especificação de sistemas orien-tados a objeto. Todas as construções do paradigma estão presentes, e a fa-cilidade do desenvolvimento visual é patente na definição das especificações.Como é importante que especificações sejam produzidas a partir de um corretoentendimento dos requisitos de uma aplicação, é necessário que tanto desen-volvedores quanto clientes participem do processo de especificação. Especi-ficações diagramáticas são mais fáceis de usar, produzir e entender por nãoespecialistas. Sendo ainda um método de especificação formal, gramáticas degrafos orientados a objeto podem ser utilizadas para verificação formal de sis-temas [Dotti et al. 2003], [Ferreira 2005] provando que uma especificação temas propriedades que dela se desejam.

Referências[Araújo Jr. and Sawyer 1998] Araújo Jr., J. and Sawyer, P. (1998). Integrating

object-oriented analysis and formal specification. Journal of the BrazilianComputer Society, 5(1).

[Baresi and Pezzè 2000] Baresi, L. and Pezzè, M. (2000). Can graph gram-mars make formal methods more human? In Workshop on Graph Transfor-mation and Visual Modeling Techniques, pages 387–394, Geneva (Switzer-land).

[Barnes 1998] Barnes, J. (1998). Programming in Ada 95. Addison-WesleyProfessional, 2nd edition. 720p.

[Bergstra et al. 1989] Bergstra, J. A., Heering, J., and Klint, P. (1989). AlgebraicSpecification. ACM Press, New York.

448

Page 63: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

[Booch et al. 1999] Booch, G., Rumbaugh, J., and Jacobson, I. (1999). TheUnified Modeling Language User Guide. The Addison-Wesley Object Tech-nology Series. Addison-Wesley, Reading.

[Breu 1991] Breu, R. (1991). Algebraic Specification Techniques in Object Ori-ented Programming Environments, volume 562 of Lecture Notes in ComputerScience. Springer-Verlag, Berlin.

[Campione et al. 2000] Campione, M., Walrath, K., and Huml, A. (2000). TheJava(TM) Tutorial. Addison-Wesley, Upper Saddle River, 3rd edition.

[Cardelli and Wegner 1985] Cardelli, L. and Wegner, P. (1985). On understan-ding types, data abstraction and polymorphism. ACM Computing Surveys,17(4):471–522.

[Clark and Taernlund 1982] Clark, K. L. and Taernlund, S.-A. (1982). Logic pro-gramming. Academic Press, London. 366p.

[Clarke et al. 1999] Clarke, E. M., Grumberg, O., and Peled, D. A. (1999). Mo-del Checking. MIT Press, Cambridge, MA. 387p.

[Cook 1990] Cook, W. R. (1990). Object-oriented programming versus abstractdata type. In de Bakker, J. W., de Roever, W. P., and Rozemberg, G., editors,Foundations of Object-Oriented Languages, volume 489 of Lecture Notes inComputer Science, pages 151–178. Springer, Berlin.

[Cook et al. 1989] Cook, W. R., Hill, W. L., and Canning, P. S. (1989). Inhe-ritance is not subtyping. In 17th Annual ACM Symposium on Principles ofProgramming Languages, POPL, pages 125–135. New York: ACM Press.

[Corradini et al. 1996] Corradini, A., Montanari, U., and Rossi, F. (1996). Graphprocesses. Fundamentae Informatica, 26(3-4):241–265.

[CSK CORPORATION 2005] CSK CORPORATION (2005). TheVDM++ Language. CSK Corporation. Available at<http://www.vdmbook.com/langmanpp_a4_001.pdf>. Visited in May,2005.

[Dijkstra 1965] Dijkstra, E. W. (1965). Solution to a problem in concurrent pro-gramming control. Communications of the ACM, 8(9):569.

[Dotti et al. 2003] Dotti, F. L., Foss, L., Ribeiro, L., and Santos, O. M. (2003).Verification of object-based distributed systems. In Najm, E., Nestmann, U.,and Stevens, P., editors, International Conference on Formal Methods forOpen Object-Based Distributed Systems, FMOODS, volume 2884 of LectureNotes in Computer Science, pages 261–275, Paris. Berlin: Springer-Verlag.

[Ehrig et al. 1996a] Ehrig, H., Heckel, R., Korff, M., Löwe, M., Ribeiro, L., Wag-ner, A., and Corradini, A. (1996a). Algebraic approaches to graph transforma-tion. Part II: single-pushout approach and comparison with double pushoutapproach. In Ehrig, H., Kreowski, H.-J., Montanari, U., and Rozemberg, G.,editors, Handbook of Graph Grammars and Computing by Graph Transfor-mation, volume 1, chapter 4, pages 247–312. World Scientific, Singapore.

449

Page 64: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

[Ehrig et al. 1996b] Ehrig, H., Kreowski, H.-J., Montanari, U., and Rozemberg,G. (1996b). Handbook of Graph Grammars and Computing by Graph Trans-formation, volume 1 (Foundations). World Scientific, Singapore.

[Ehrig and Löwe 1993] Ehrig, H. and Löwe, M. (1993). Parallel and distributedderivations in the single-pushout approach. Theoretical Computer Science,109:123–143.

[Ferreira 2005] Ferreira, A. P. L. (2005). Object-Oriented Graph Grammars.PhD thesis, Universidade Federal do Rio Grande do Sul, Porto Alegre.

[Ferreira and Ribeiro 2003] Ferreira, A. P. L. and Ribeiro, L. (2003). Towardsobject-oriented graphs and grammars. In Najm, E., Nestmann, U., andStevens, P., editors, International Conference on Formal Methods for OpenObject-Based Distributed Systems, FMOODS, volume 2884 of Lecture Notesin Computer Science, pages 16–31, Paris. Berlin: Springer-Verlag.

[Ferreira and Ribeiro 2005] Ferreira, A. P. L. and Ribeiro, L. (2005). A graph-based semantics for object-oriented programming constructs. Electronic No-tes in Theoretical Computer Science, 122:89–104.

[Fitting 1996] Fitting, M. (1996). First-order logic and automated theorem pro-ving. Springer, New York, 2nd edition.

[Fitzgerald et al. 2005] Fitzgerald, J., Larsen, P. G., Mukherjee, P., Plat, N., andVerhoef, M. (2005). Validated Designs for Object-oriented Systems. Springer,New York.

[Gadducci 1996] Gadducci, F. (1996). On the Algebraic Approach to Concur-rent Term Rewriting. PhD Thesis, Dipartimento di Informatica, Università diPisa, Pisa, Italy.

[Garey and Johnson 1999] Garey, M. R. and Johnson, D. S. (1999). Computersand intractability: a guide to the theory of NP-completeness. W. H. Freeman,New York.

[Goguen and Malcom 1996] Goguen, J. A. and Malcom, G. (1996). Algebraicsemantics of imperative programs. MIT Press, London.

[Holzmann 1997] Holzmann, G. J. (1997). The model checker SPIN. IEEETransactions on Software Engineering, 23(5):1–17.

[Hopcroft 1969] Hopcroft, J. E. (1969). Formal languages and their relation toautomata. Addison-Wesley, Reading.

[Hopcroft et al. 2001] Hopcroft, J. E., Motwani, R., and Ullman, J. D. (2001). In-troduction to automata theory, languages, and computation. Addison-Wesley,Boston, 2nd edition.

[Huth and Ryan 2000] Huth, M. R. A. and Ryan, M. D. (2000). Logic in Compu-ter Science: Modelling and reasoning about systems. Cambridge UniversityPress, Cambridge.

450

Page 65: Programação Orientada a Objeto com Grafos

Programação Orientada a Objeto com Grafos

[Kennaway 1995] Kennaway, R. (1995). Infinitary rewriting and cyclic graphs.Electronic Notes in Theoretical Computer Science, 2. 14p.

[Kosko 1992] Kosko, B. (1992). Neural networks and fuzzy systems: a dyna-mical systems approach to machine intelligence. Prentice-Hall, EnglewoodCliffs.

[Lewis and Papadimitriou 1998] Lewis, H. R. and Papadimitriou, C. H. (1998).Elements of the Theory of Computation. Prentice Hall, Upper Saddle River,2nd edition.

[Lischner 2000] Lischner, R. (2000). Delphi in a Nutshell. O’Reilly.

[Martin 1996] Martin, J. C. (1996). Introduction to Languages and the Theoryof Computation. WCB/McGraw-Hill, 2nd edition.

[Meyer 1991] Meyer, B. (1991). Eiffel : The Language. Prentice Hall.

[Milner 1989] Milner, R. (1989). A Calculus of Communicating Systems.Springer-Verlag, Berlin.

[Muhammad and Ferreira 2003] Muhammad, H. H. and Ferreira, A. P. L.(2003). Exploração de reflexão computacional através de um modelo deobjetos sem classes. Revista Eletrônica de Iniciação Científica, 3(3):1–15.

[Nagl 1986] Nagl, M. (1986). Set theoretic approaches to graph grammars. InEhrig, H., Nagl, M., Rozenberg, G., and Rosenfeld, A., editors, 3rd Inter-national Workshop on Graph Grammars and their Application to ComputerScience, volume 291 of Lecture Notes in Computer Science, pages 41–54,Warrenton, Virginia, USA. Berlin: Springer-Verlag.

[Nikolopoulos 1997] Nikolopoulos, C. (1997). Expert Systems. Marcel Dekker,New York.

[Reade 1995] Reade, C. (1995). Elements of Functional Programming.Addison-Wesley, Wokingham, 2nd edition.

[Russell and Norving 1995] Russell, S. J. and Norving, P. (1995). Artificial In-telligence: a modern approach. Prentice-Hall, Upper Saddle River.

[Smith 1999] Smith, G. (1999). The Object Z Specification Language. KluwerAcademic Publishers.

[Smith 1992] Smith, G. P. (1992). An Object-Oriented Approach to Formal Spe-cification. PhD thesis, Department of Computer Science, University of Que-ensland, Brisbane.

[Sterling and Shapiro 1994] Sterling, L. and Shapiro, E. Y. (1994). The Art ofProlog : Advanced Programming Techniques. MIT Press, Cambridge, 2ndedition.

[Stroustup 2000] Stroustup, B. (2000). The C++ Programming Language.Addison-Wesley, Upper Saddle River, 3rd edition.

451

Page 66: Programação Orientada a Objeto com Grafos

Ferreira e Ribeiro

[Tanenbaum 1992] Tanenbaum, A. S. (1992). Modern Operating Systems. Si-mon & Schuster, Upper Saddle River, NJ.

[Tanenbaum and Woodhull 1997] Tanenbaum, A. S. and Woodhull, A. S.(1997). Operating systems: design and implementation. Prentice Hall, UpperSaddle River, 2nd edition.

[Thomas and Weedon 1997] Thomas, P. and Weedon, R. (1997). Object-oriented programming in Eiffel. Addison-Wesley, Harlow.

[Ungar et al. 1991] Ungar, D., Chambers, C., Chang, B.-W., and Hölzle, U.(1991). Organizing programs without classes. Lisp and Symbolic Compu-tation, 3(4).

452