Escolar Documentos
Profissional Documentos
Cultura Documentos
Para a disciplina de Projecto do 5 Ano do Curso de Engenharia Informtica Ramo Computadores e Sistemas
Pedro Miguel Flix Alpio N 920385 E-mail: pedro.alipio@clix.pt
ndice
1. INTRODUO 1.1 - Os principais paradigmas da computao 1.2 Histria do Mozart-Oz 1.3 Resumo das Caractersticas do Oz 3 2. A LINGUAGEM OZ 2.1 O Modelo de programao do Oz 2.2 Comparao entre o Oz e o Prolog 2.3 Comparao entre o Oz e o Java 3. O OZ DISTRIBUDO 3.1 Caractersticas do Oz Distribudo 3.2 O grafo de distribuio 3.3 A Arquitectura de Implementao 3.3.1 O Motor Estendido 3.3.2 A Camada de Protocolo 3.3.3 A Camada de gesto de memria 3.3.4 Camada de Rede 3.4 Computao Aberta 3.4.1 Conexes e tickets 3.4.2 Servidores de computao 3.5 Deteco e Tratamento de Falhas 3.5.1 O Principio da deteno 3.5.2 Falhas no grafo da distribuio 3.5.3 Handlers e watchers 3.6 Controlo de Recursos e Segurana 3.6.1 Sites Virtuais 4. TUTORIAL DE OZ 7 7 8 9 11 11 14 14 16 18 19 20 21 21 22 22 22 22 23 23 24 25 25 26 27 28
4.1 O Ambiente de Desenvolvimento 4.1.1 Arrancar o ambiente de desenvolvimento 4.1.2 O primeiro programa 4.1.3 Principais caractersticas do OPI 4.2 Introduo programao em Oz 4.3 Os tipos bsico de dados 4.3.1 Instanciao de variaveis 4.3.2 Nmeros 4.3.3 Literais 4.3.4 Registos e Tuplos 4.3.6 Listas 4.3.7 Strings Virtuais 4.4 Igualdade e Teste de Igualdade 4.4.1 Teste de Igualdade 4.5 Estruturas Bsicas de Controlo e Procedimentos 4.5.1 A instruo vazia 4.5.2 A instruo condicional if 4.5.3 Procedimentos 4.5.4 Lexical Scoping 4.5.5 Semntica dos procedimentos 4.5.6 Inicializao de variveis 4.5.7 Pattern Matching 4.5.8 Aninhamento de instrues 4.5.9 Procedimentos como valores 4.5.10 Abstraces de controlo 4.6 Tratamento de Excepes 4.6.1 As excepes do sistema 4.7 Mdulos e Interfaces 4.8 Concorrncia 4.8.1 Tempo 4.8.2 Comunicao entre streams 4.8.3 Prioridades das Threads 4.8.4 Execuo orientada ao pedido 4.8.5 Deteco de terminao de threads 4.8.6 Composio concorrente 4.9 Tipos de dados baseados em estados 4.9.1 Ports 4.9.2 Comunicao Cliente-Servidor 4.9.3 As clulas 4.9.4 Chunks 4.9.5 Locks
28 28 29 30 34 35 35 35 36 36 38 39 39 40 41 41 41 43 45 45 46 47 49 50 51 52 53 54 56 58 58 60 61 62 63 64 64 65 66 67 68
4.10 Classes e Objectos 4.10.1 Implementao de Classes utilizando estruturas mais primitivas 4.10.2 Implementao de Objectos utilizando estruturas mais primitivas 4.10.3 As Classes em Oz 4.10.4 Chamadas estticas a mtodos 4.10.5 Herana de classes 4.10.6 Propriedades 4.10.7 Classes parametrizadas 4.10.8 Mtodos pblicos e privados 4.10.9 Valores por omisso dos argumentos 4.11 Objectos e Concorrncia 4.11.1 Trocas atmicas em atributos 4.11.2 Locks de threads reentrantes 4.11.3 Aplicando locks a objectos 4.11.4 Canal FIFO concorrente 4.11.6 Eventos 4.11.7 Objectos Activos 4.12 Arrays e Dicionrios 4.13 Programao Lgica 4.13.1 Armazenamento de restries 4.13.2 Espaos computacionais 4.13.3 Vinculao e desvinculao de restries 4.13.4 Disjunes 4.13.6 Execuo orientada determinao 4.13.7 Lgica Condicional 4.13.8 Expresses condicionais paralelas 4.13.9 Programas no deterministicos e busca 4.13.10 Exemplos 5. TUTORIAL DE OZ DISTRIBUDO 5.1 Nomes Globais 5.1.1 Conectar aplicaes atravs de tickets 5.1.2 Estruturas de dados persistentes usando pickes 5.1.3 Computaes Remotas e Functors 5.1.4 Servidores 5.1.5 Servidor de computaes 5.1.6 Servidor de computaes com funtors 5.1.7 Servidor dinamicamente extensvel 5.2 Agentes Mveis 5.2.1 Instalao de Agentes 5.2.2 Programao de agentes 5.2.3 A Definio do servidor de agentes 5.3 Tolerncia a falhas
5.3.1 O servidor de Ol Mundo com tolerncia a falhas 5.3.2 Tolerncia a falhas em objectos estacionrios 5.3.3 Tolerncia a falhas usando guardas 5.3.4 Tolerncia a falhas baseada em excepes 6 PROGRAMAO GRFICA 6.1 Toplevel e Objectos Widget 6.1.1 Frames 6.1.2 Labels 6.1.3 Imagens 6.1.4 Mensagens 6.2 Gestores de Geometria 6.2.1 O Packer 6.2.2 Grids 6.3 Outros Widgets 6.3.1Botes e Aces 6.3.2 CheckButtons, RadioButtons e variveis 6.3.3 Menus 6.3.4 Eventos 6.3.5 Entries 6.3.6 Scales 6.3.7 Listboxes 6.3.8 Manipular o toplevel 6.3.9 DialogBoxes predefinidas 6.4 O Canvas 6.4.1 Criar um grfico de barras 6.4.2 Eventos 6.5 Caixas de Texto 6.5.1 Manipulao do texto 6.5.2 Etiquetas de texto e marcas 6.6 Ferramentas para o Tk 6.6.1 Dialogs 6.6.2 Mensagens de Erro 6.6.3 Barras de Menus 6.6.4 Listas de Imagens 7. CONCLUSO APNDICE A Os programas dos testes de performance entre o Oz e o Java A.1 Produtor Consumidor Centralizado em Java A.2 Produtor Consumidor Centralizado em Oz
103 106 107 109 111 111 111 112 113 113 113 113 115 115 116 116 117 118 119 120 120 121 121 121 122 123 124 124 124 125 125 126 126 127 128 129 129 129 131
A.3 Produtor Consumidor Distribudo em Java A.4 Produtor Consumidor distribudo em Oz APNDICE B Nomes de Cores APNDICE C Glossrio de alguns termos BIBLIOGRAFIA
1. Introduo
As linguagens de programao descrevem comportamentos computacionais baseando-se em diferentes filosofias ou paradigmas. Uma distino mais rude dos paradigmas divide-os em duas categorias : programao baseada e no baseada em estados. A programao baseada em estados representa dados que mudam ao longo do tempo, enquanto que, a no baseada em estados, representa dados que so imutveis depois de serem criados. A distino entre estas duas filosofias importante pois a programao baseada em estados apresenta um modelo de programao que consiste numa aproximao ao mundo real, enquanto o modelo no baseado em estados permite uma maior simplicidade no raciocnio. A evoluo das linguagens de programao baseadas em estados culminou no modelo orientado a objectos, enquanto as no baseadas em estados (linguagens declarativas) deram origem computao directa e indirecta. Da computao directa nasceram as linguagens funcionais. Da computao indirecta surgiram as linguagens lgicas. A programao multi-paradigma consiste na integrao de vrios paradigmas num nico modelo. Neste modelo, as vrias formas de computao podem ser entendidas, como partes de uma filosofia nica. Esta forma de computao permite um estilo natural de programao, isto , adaptar a cada problema especifico que surge no decorrer da elaborao de uma aplicao, o paradigma mais adequado implementao de um algoritmo para o resolver. Por exemplo, para problemas relacionados com avaliao de funes, usar-se-ia o paradigma funcional, para problemas relacionados com informao parcial, usar-seia o paradigma da programao baseada em restries, para problemas em que seja necessrio representar entidades do mundo real ou estados, usar-se-ia o paradigma da programao orientada a objectos.
Programao Lgica
A programao lgica consiste na realizao de computaes como dedues. As caractersticas principais destas linguagens utilizadas pelo Oz so a utilizao de variveis lgicas e a pesquisa de solues (por exemplo: backtracking). Este tipo de programao deu mais tarde origem computao especulativa com base em informao parcial, ou seja, a computao baseada em restries. A linguagem mais conhecida que implementa este paradigma o Prolog.
Programao Funcional
As principais caractersticas das linguagens funcionais usadas pelo Oz so a utilizao de entidades first-class (funoes, variveis, etc... podendo ser passadas como argumento), sintaxe composicional e lexical scoping (est relacionado com o
espao contextual que a varivel abrange). Estes conceitos irao ser estudados em maior detalhe ao longo deste documento. Uma das linguagens que implementa este paradigma o Haskell.
Programao
Programao Orientada a Objectos
O Oz uma linguagem concorrente orientada a objectos. Esta linguagem pode inicialmente ser programada de modo similar a outras, como por exemplo o Java. O programador, atravs da experiencia, tender a simplificar os seus programas, usando os poderosos conceitos de execuo dependente no fluxo de dados e procedimentos first-class. O Oz possui as estruturas bsicas encontradas em todas as linguagens orientadas a objectos, tais como : classes, objectos, mtodos, atributos e herana.
Programao Concorrente
O Oz iminentemente uma linguagem concorrente. O sistema Mozart implementa um sistema de threads ultraleves utilizando um escalonamento preemptivo baseado na diviso do tempo (time slice) de processamento pelas threads Fair scheduling. Possui dois mecanismos de sincronizao : baseados no fluxo dos dados ou de forma transparente pela utilizao de variveis lgicas.
Multi-Paradigma
Quase todas as linguagens de programao tm um modelo baseado num s paradigma. O Oz usa de forma coerente e simples os paradigmas: funcional, orientado a objectos, e programao lgica. Isto possivel porque possui uma implementao muito geral e poderosa do paradigma de programao concorrente baseada em restries.
Inferncia
Programao Baseada em Restries
O Oz uma poderosa linguagem de programao por restries com variveis lgicas, domnios finitos, conjuntos finitos, rvores relacionais e restries de registo. O sistema competitivo em desempenho, com as solues comerciais, mas mais expressivo e flexvel, disponibilizando espaos computacionais fistclass, estratgias programveis de pesquisa de solues, uma ferramenta grfica para a explorao interactiva das rvores de pesquisa, motores de pesquisa paralelos explorando a possibilidade de distribuir a computao na rede e um interface por programao para construir eficientes sistemas novos de restries.
Programao Lgica
O Oz implementa tanto programao declarativa lgica directa como indirecta. Possui poderosas ferramentas construdas sobre os conceitos espaos de computao first-class e disjunes. Torna o Mozart ideal para a implementao de sistemas Multi-Agentes Inteligentes ou sistemas de pesquisa paralelos.
Distribuio
Sistemas Distribudos Abertos
O sistema Mozart a plataforma ideal para este tipo de sistemas porque torna a rede completamente transparente. Cria a iluso de uma rea de armazenamento comum, que se encontra na realidade estendida a varias localizaes. O suporte para isso, so protocolos bastante eficientes. O Mozart tem
controlo absoluto sobre as comunicaes na rede permitindo o uso de modo bastante eficiente os recursos por ela disponibilizados. Permite tambm fcil desenvolvimento de aplicaes robustas, com mecanismos de tolerncia a falhas.
Agentes Mveis
Tendo uma tecnologia de componentes dinmicos, suporte para computao aberta, e todas as outras caractersticas, o Mozart uma plataforma ideal para programao de agentes mveis. Uma computao capaz de criar computaes num espao distribudo e dinmico.
Plataforma
Compatibilidade
Tal como o Java, o Oz do tipo escreve um vez, executa em qualquer sitio possui mecanismos locais e distribudos de garbage colection. O Oz possui uma virtual machine, que portvel e pode ser executada em sistemas Unix ou Windows.
Interface Grfica
O sistema Mozart tem uma biblioteca orientada a objectos que disponibiliza funcionalidades de interface grfico baseadas em Tcl/Tk.
10
2. A Linguagem Oz
O Oz uma linguagem poderosa que se baseia num pequeno conjunto de conceitos simples. Este captulo tenta explicar o modelo de programao do Oz,e ainda compar-lo com outras linguagens semelhantes. Apesar das razes do Oz serem a programao lgica concorrente baseada em restries, esta linguagem pretende ir muito mais longe. O objectivo criar uma infra-estrutura slida para qualquer tipo de computao, no apenas para a programao declarativa.
S1
S1
Sn
X=23 Z Y=Pessoa(idade:27)
No memria fisica Contm variveis e atribuies Apenas admite operaes vlidas para as entidades envolvidas
O modelo do Oz constitudo por uma rea de armazenamento abstracta acedida por threads de fluxo de dados. As thread executam sequncias de expresses e bloqueiam quando na falta de disponibilidade dos dados. A rea de armazenamento no a memria fsica. S autoriza operaes que sejam validas para as entidades envolvidas, isto , no permite apontadores tipo linguagem C, nem casting. A rea de armazenamento tem trs componentes: a rea de restries, que contem as variveis e os valores a elas atribudos (instanciaes); a rea de procedimentos, que contem a definio dos procedimentos; e finalmente a rea das clulas, que contm apontadores mutveis (Cells). A rea de armazenamento de restries e a rea de armazenamento de procedimentos so monotnicas ou monotonas, isto , os dados nelas contidos no podem ser alterados ou removidos, apenas se podem adicionar. As threads, bloqueiam com a no disponibilidade de dados que necessitem na rea armazenamento de restries.
11
<Expresso> ::= | | | | | | | | | | | | | | | |
<Expresso1> <Expresso2> X = f(l1:Y1 ... ln:Yn) X = <nmero> X = <atomo> X = <booleano> {NewName X} X = Y local X1 ... Xn in S1 end proc {X Y1 ... Yn} S1 end {X Y1 ... Yn} {NewCell Y X} {Exchange X Y Z} {Access X Y} if B then S1 else S2 end thread S1 end try S1 catch X then S2 end raise X end
As threads executam uma linguagem que consiste num forma reduzida do Oz designada de OPM (Oz Programming Model). Na figura 1, encontra-se descrito o sintaxe desta linguagem. As sequncias de expresses so reduzidas de forma sequencial na thread. Os valores (Registos, nmeros, etc ...), so introduzidos explicitamente e podem ser igualados a variveis. Todas as variveis so lgicas e definidas num espao explicito definido pela palavra local. Os procedimentos so criados em tempo de execuo atravs da palavra proc, e referenciados por uma varivel. Na rea de armazenamento so representados na forma :z/E, em que o nome, o z um argumento formal (varivel), e o E o corpo do procedimento. A reduo de um procedimento na forma proc{x y} E, processa-se escolhendo um nome , indicando na rea de armazenamento de restries que x = , escrevendo de seguida na rea de armazenamento de procedimentos o novo procedimento (:z/E). A chamada ao procedimento x ( {x y} ), bloqueia enquanto no estiver na rea de armazenamento de procedimentos a definio :z/E para a varivel x, que por sua vez est definida na rea de armazenamento de restries sob a forma de x=. Neste caso desta chamada a reduo feita substituindo todas as ocorrncias de z no corpo do procedimento E por y. As variveis de estados so criadas explicitamente atravs de NewCell, que cria uma clula que consiste num apontador altervel para rea de armazenamento de restries. As clulas podem ser alteradas atravs de Exchange e Access. As condies so implementadas atravs da palavra chave case que bloqueia, enquanto a condio, na rea de armazenamento de restries, no for verdadeira ou falsa. A palavra chave if reservada para aplicaes baseadas em restries. As threads, so criadas de forma explicita atravs da palavra thread, e ficam com um identificador prprio. O tratamento de excepes feito atravs das palavras try que determina o espao de abrangncia e catch que indica a aco a tomar caso ocorra nesse espao uma excepo. As expresses do Oz completo so executadas traduzindo essas expresses noutras na forma reduzida ou OPM. O Oz completo disponibiliza outras estruturas, tais como objectos, classes, locks reentrantes, e ports. Que consistem no seguinte:
12
Objectos
Um objecto essencialmente um procedimento com um argumento ({Obj M}) que referencia uma clula escondida pelo lexical scoping. Essa clula detm o estado do objecto. O argumento M indexa o mtodo na tabela de mtodos do objecto. O mtodo um procedimento que a partir de um determinado estado calcula um novo estado.
Classes
A classe um registo uma tabela de mtodos e os nomes dos atributos. Os conflitos de herana mltipla so resolvidos na altura da criao da criao da classe, de modo a ser possvel construir a tabela de mtodos.
Locks Reentrantes
Um lock reentrante consiste num procedimento com um argumento ( {Lck P} ) usado para efectuar excluso mtua (por exemplo podem ser usados para excluso mtua nos corpos dos mtodos, criado uma espcie de entrys de objectos protegidos do ADA95). A thread que acede ao lock pode reentrar nele. Isto permite a utilizao de Nesting. O lock libertado quando a thread no seu corpo terminar, ou se surgir uma excepo durante a execuo, que faa abandonar corpo do lock.
Ports
Os Ports canais assncronos que suportam um modelo de comunicao um para muitos. Estas estruturas encapsulam streams, que consistem em listas com a cauda no instanciada. A operao ( {Send P M} ) adiciona M ao fim do stream encapsulado por P. Envios sucessivos partindo da mesma thread, aparecem no stream, com a mesma ordem de envio. Mais tarde ir ser detalhado como se implementa cada uma destas estruturas.
13
Restries Controlo
High-order Estados
Tabela 2: Estatsticas relativas s diferena de desempenho entre o Oz e o Java executando uma aplicao Produtor/Consumidor (jdk 1.2 e mozart 1.0.1 num solaris UltraSparc II)
Em aplicaes distribudas o desempenho do Java muito menor que o do Mozart. A principal razo que para cada elemento que o Produtor produz, enviada uma mensagem de rede, e a thread sincronizada depois do retorno de uma chamada a RMI (Remote method evocation). O sistema Mozart agrupa automaticamente grupos de elementos que o Produtor produz, consequentemente reduzindo o numero de mensagens na rede. Para alm disso, no Mozart apenas o consumidor necessita ser sincronizado. O java pode ainda ser optimizado para a lgica Produtor/Consumidor, mas isso iria fazer com que o programa fosse bastante maior e mais complexo, e tornaria o programa distribudo cada vez mais distinto da verso centralizada. Conclui-se que a programao distribuda eficiente consideravelmente mais difcil de implementar em Java que em Mozart.
14
15
3. O Oz Distribudo
Cada vez mais os computadores so ligados em redes. A transmisso de informao de um ponto para outro qualquer no mundo, tornou-se trivial. A internet, construda sobre a famlia de protocolos TCP/IP, tem vindo a duplicar o numero de servidores desde 1981. O trabalho colaborativo que inicialmente consistia em trocas de e-mail e newsgroups, usa agora tecnologias como workflow, multimdia, e ambientes verdadeiramente distribudos. Fontes de informao heterogneas e fisicamente separadas, so ligadas. Surgem os agentes, permitindo a delegao de tarefas na rede. Criam-se protocolos seguros que possibilitam o comercio electrnico. Apesar de todo este desenvolvimento espantoso, a computao distribuda continua um grande desafio. Um sistema distribudo um conjunto de processos autnomos, interligados por uma rede. Para especificar que os processos no correm necessariamente na mesma mquina, deu-se-lhes o nome de sites. Um sistema como este muito diferente de um s processo a correr numa mquina. Estes sistemas so inerentemente concorrentes e no deterministicos. No existe informao global nem tempo global. Os atrasos na comunicao entre os processos imprevisvel. Existe uma grande probabilidade de falhas localizadas. O sistema partilhado, tendo os utilizadores, de estar protegidos dos outros utilizadores e dos seus agentes computacionais. Uma aplicao distribuda deve ter bom desempenho, ser segura, permitir comunicao de forma simples com outras aplicaes. Actualmente, o desenvolvimento de uma aplicao distribuda com estas caractersticas, requer conhecimentos muito para l dos que so necessrios para desenvolver uma aplicao numa mquina s. Por exemplo, uma aplicao Cliente-Servidor pode ser desenvolvida em Java-RMI. Uma determinada aplicao pode comunicar com outra atravs de um implementao de CORBA (por exemplo o Orbix). Nestes casos, ambas as ferramentas so insatisfatrias. A reorganizao da aplicao para suportar uma estrutura distribuda implica rescrever toda a aplicao. O java no usa threads de fatias temporais, por isso, a reorganizao em Java exige profundas alteraes na aplicao. Para alm disso, cada nova funcionalidade que acrescentada, por exemplo adicionar tolerncia a falhas, a complexidade da aplicao aumenta bastante. Para se dominar cada problema, necessrio estudar e compreender vrias ferramentas complexas para alm do ambiente base do Java, isto , algum que apenas saiba desenvolver aplicaes centralizadas no est qualificado para desenvolver aplicaes distribudas. Algumas solues foram tentadas para integrar mecanismos de resoluo de problemas de vrias reas, numa nica plataforma. Por exemplo, a Ericsson Open Telecom Platform (OTP), baseada na linguagem Erlang, integra uma soluo para estruturas distribudas e tolerncia a falhas. O Erlang transparente quanto utilizao da rede a nvel de processo, isto , as mensagens entre processos so enviadas da mesma forma independentemente dos processos estarem ou no na mesma mquina. A OTP vai bastante mais longe que plataformas mais populares tais como o Java, e tem sido usado em produtos comerciais relacionados com telecomunicaes (Software para centrais telefnicas PBX, routers ATM, etc...) . O sucesso do Erlang sugere aumentar o alcance das ferramentas de desenvolvimento de aplicaes a outras reas da computao distribuda. Existem
16
quatro reas, nomeadamente estrutura de distribuio, computao aberta, tolerncia a falhas e segurana. Se for includa a funcionalidade da aplicao, existiro cinco principais preocupaes: Funcionalidade: O que que a aplicao faz, ignorando tudo o que diz respeito distribuio. Estrutura de distribuio: Repartir a aplicao por vrios sites. Computao Aberta: Aplicaes independentes que comunicam entre si. Tolerncia a falhas: A aplicao continuar a providenciar um servio mesmo que ocorram falhas parciais. Segurana: A capacidade da aplicao continuar a providenciar um servio mesmo que haja interferncia intencional. Uma parte muito importante da tolerncia a falhas e segurana o controlo dos recursos. Uma soluo possvel para integrar estas preocupaes, separar a funcionalidade das outras (figura 2). Idealmente, o maior volume da aplicao deveria ser ocupado com o cdigo relacionado com as suas funcionalidades, as outras preocupaes deveriam ser, nada mais, do que pequenos mdulos adicionais. O primeiro passo para atingir isso, ser separar a funcionalidade da estrutura de distribuio. O sistema dever ser transparente relativamente ao uso da rede. Para isso as computao de aplicaes centralizadas e distribudas tero de ser semelhantes, ou seja, dever ser possvel programar a aplicao sem ter em conta a existncia de uma rede de computadores (network-transparent system). Outro aspecto importante, manter, por parte do programador, o controlo sobre a localizao das computao e das comunicaes na rede, decidindo onde so executadas e detendo o controlo sobre a mobilidade e replicao dos dados e do cdigo (network-aware system).
Estrutura de distribuio Funcionalidade Computao Aberta
Estrutura de distribuio Computao Aberta Tolerncia a falhas Tolerncia a falhas Funcionalidade Controlo de recursos e segurana
17
18
falhas. Suporta uma poltica de segurana dentro da prpria linguagem e possui primitivas para o controlo de recursos baseadas no conceito de site virtual. No Oz distribudo, o desenvolvimento de uma aplicao esta separado em duas partes independentes. Em primeiro lugar, apenas a arquitectura lgica da tarefa considerada. A aplicao desenvolvida em Oz, sem que se tenha em ateno a distribuio da sua computao por diversos sites. Assim pode-se verificar a segurana e a durabilidade da aplicao executando em apenas um site. Depois, a aplicao tornada eficiente pela especificao dos comportamentos de rede nas suas entidades. Em particular, a mobilidade das entidades com estados (objectos), deve ser especificada. Por exemplo, alguns objectos podem ser colocados em certos sites, enquanto outros podem ter um caracter mvel. O Oz distribudo expande o Oz com quatro algoritmos complexos. Trs deles foram desenvolvidos para entidades especificas da linguagem, nomeadamente variveis lgicas, objectos-registos, e objectos-estados de objectos. As variveis lgicas so instanciadas atravs do variable binding protocol. Os objectos-registos so replicados pelos sites atravs do lazy replication protocol. Os objectos-estados so movidos entre sites atravs do mobile state protocol. O quarto protocolo um algoritmo de recolha de lixo (garbage collection) distribudo. Este mecanismo uma parte da gesto de entidades distribudas, serve portanto de suporte aos outros protocolos.
Clula
O modelo pode ser entendido de uma forma simples mas precisa usando o conceito de grafo de distribuio. O grafo de distribuio pode ser obtido em dois passos a partir de um estado arbitrrio do sistema. O primeiro passo independente da distribuio. Modela-se o estado de execuo utilizando um grafo chamado grafo de linguagem, onde cada entidade da linguagem com a excepo dos objectos que correspondam a ns (Figura 3). No segundo passo, introduz-se a noo de site. Assume-se um conjunto finito de sites e coloca-se cada n no seu site respectivo (Figura 4). Se um n for referenciado por pelo menos outro n noutro site, organiza-se um conjunto, por exemplo para N2, cria-se o conjunto {P1,P2,P3,M}. A este conjunto d-se o nome de estrutura de acesso do n. Uma estrutura de acesso e constituda por um n proxy Pi para cada site que referencia o n e um n de gesto M para toda a estrutura. O grafo que resulta, contendo tanto os ns locais como as estruturas de acesso necessrias, chamado de grafo de distribuio. Os exemplos do funcionamento dos protocolos sero apresentados segundo esta notao. A cada estrutura de acesso dada um endereo global nico no sistema global. Este endereo global codifica diversa informao incluindo o site de gesto.
19
Os ns proxy so unicamente identificados pelo par (endereo global, site). Em cada site, os endereos globais indexam uma tabela que referencia o proxies. Cada site tem pelo menos um proxy. As mensagens entre ns so enviadas nas estruturas de acesso. No corpo das mensagens existem referencias a ns no site destino. Esses ns so identificados pelo endereos globais das suas estruturas de acesso. Quando as mensagens chegam, os ns so pesquisados na tabela do site. Os procedimentos e os outros valores (registos, nmeros, etc) so copiados de forma eager, isto , no resultam em estruturas de acesso. Um procedimento enviado uma vez s para um site e apenas existe uma cpia nesse site. O procedimento consiste numa clausula e um bloco de cdigo, sendo-lhes atribudo um endereo global. As mensagem apenas contm o endereo global. Depois de serem recebidas imediatamente feito o pedido dos blocos de cdigo e clausulas que faltam.
Estrutura de acesso para N2
N1
N2
N3
N1
P1
P2
P3
N3
Site 1
Site 2
Site 3
Site 1
Site 2
Site 3
Camada de protocolo
Motor estendido
20
M 2 3 P P 4 1.A thread inicia o processo de instanciao e bloqueia. 2.O proxy faz um pedido de instanciao 3.O n gestor (M) concede a intanciao e efectua um multicast para todos os proxies 4.O proxy informa a thread permitindo que ela continue a execuo 3 1 T
Este motor expande o Oz centralizado sob a forma de um interface para a camada de protocolo. O motor reconhece certos eventos e passa-os camada de protocolo. Um exemplo tpico a instanciao de variveis (figura 6) atravs dos seus proxies. A camada de protocolo pode tambm desencadear operaes do motor, por exemplo chegada do contedo de uma clula vindo de outro site, ou a passagem de procedimentos da rede para o motor.
21
movido de um proxy para outro. O proxy que necessitar de ler um estado pede ao gestor, este decide quem ir aceder a seguir e envia uma mensagem ao proxy respectivo.
Esta camada converte as estruturas de distribuio do grafo em sequncias de bytes para ser enviadas atravs da rede. As mensagens trocadas entre ns do grafo de distribuio podem referenciar subgrafos. Quando os subgrafos so transportados de um site para outro, os seu ns tornam-se membros das estruturas de acesso que tm ns tanto no site emissor como no receptor. As estruturas de acesso so identificadas por um endereo nico na rede chamado endereo de rede (network address). Este endereo recuperado quando a estrutura de acesso que identifica deixa de ser acessvel localmente de nenhum dos seus sites. Esta situao detectada por mecanismos locais de garbage collection com um mecanismo de crdito. Cada endereo de rede criado com um numero grande fixo de crditos. O n gestor inicialmente detm os crditos e atribui-os a qualquer site (incluindo mensagens em transito) que tm o endereo de rede. Quando um site deixa de referenciar localmente a estrutura de acesso os crditos so devolvidos ao gestor. Quando o gestor recupera todos os crditos e deixa de ser referenciado localmente o endereo de rede recuperado (libertado).
22
conexes entre sites independentes. O sistema, na fase final do seu desenvolvimento deve garantir segurana, tanto a nvel das conexes como a nvel dos tickets. O site servidor cria o ticket atravs do qual os sites clientes podem estabelecer a conexo. O ticket consiste numa string de caracteres que pode ser guardada e transportada de qualquer forma que suporte texto, por exemplo por correio electrnico, modem, etc... O ticket identifica o site servidor e a entidade da linguagem qual ser feita uma referencia remota. Podem ser feitas conexes independentes a diferentes entidades num mesmo site. O estabelecimento de uma conexo gera uma conexo a nvel da camada de rede (por exemplo TCP), e gera tambm no espao computacional do Oz, uma referencia no site cliente a uma entidade da linguagem no lado do site servidor. Isto pode ser implementado de vrias formas, passando procedimentos sem argumentos, unificando duas variveis, ou passando um port que ser utilizado para posteriormente para enviar valores. Depois de uma conexo inicial ter sido criada, todas as outras que a aplicao necessitar podem ser geradas a partir das abstraces disponibilizadas pela linguagem. Por exemplo, possvel definir uma classe C num site, passar C para outro site, definir a classe D derivada de C nesse site, e finalmente passar D para o site inicial. Existem dois tipos de tickets: one-shot tickets para conexes um para um, e many-shot tickets para conexes muitos para um.
23
24
Site A
Site B
Site C
M P P
M P P
Site D
Site E
Site F
A causa de uma falha no Oz distribudo est relacionada com falhas num ou mais sites, ou com a falha de uma rea da rede. Estas situaes revelam-se nas estruturas de acesso do grafo da distribuio. Uma estrutura de acesso afectada se tem pelo menos um n que se situe num site com falha ou se tem pelo menos uma ligao estraves de uma rea da rede com falha. Muitas vezes estruturas de acesso continuam a funcionar apesar de serem afectadas. Por exemplo, um objecto pode continuar a ser usado apesar de ter uma referencia remota a um site em falha. Uma estrutura de acesso falha quando os sites no conseguem operar nela. Isto pode suceder quando os componentes principais da estrutura de acesso falham, por exemplo, quando falha o n de gesto. Tendo em conta que as redes podem ter falhas temporrias, tambm as falhas das estruturas de acesso podem ter um caracter temporrio ou permanente.
25
revelando-se na linguagem sob a forma de entidades da linguagem (objectos, variveis e ports). Quando h um problema a efectuar uma operao efectuada sobre uma entidade, essa operao por omisso, bloqueia indeterminadamente. Qualquer outro comportamento deve ser explicitamente especificado pelo programador. Para isso devem ser instalados watcher e handlers na entidade. Um handler invocado se for detectado um erro quando tentada a execuo de uma operao sobre uma entidade (deteco lazy). Um watcher invocada quando um erro detectado para uma entidade, mesmo que nenhuma operao seja tentada sobre essa entidade (deteco eager). A semntica dos handlers e dos watchers bastante simples. Se a tentativa de execuo de uma operao falha, se existir um handler com uma condio de trigger que seja verificada, efectuada uma chamada a esse handler. O funcionamento idntico para os watchers, se o sistema verificar uma falha de uma determinada entidade, todos os watchers so verificados e aquelas que tiverem condies de trigger que sejam verdadeiras, so executados em threads. Os handlers e os watchers tem dois argumentos: o primeiro diz respeito entidade que falhou e o segundo ao tipo de erro. Os handlers podem ser instalados em entidades por site e por thread. Os handlers baseados em threads sobrepem-se aos baseados em sites, isto , se forem ambos aplicados os sistema apenas responde ao handler baseado em threads. Os watchers podem ser instalados por site ou por entidade. So passados trs argumentos para utilizar os handlers e os watchers: a entidade, informao de controlo, e o prprio handler ou watcher. A informao de controlo consiste no tipo de erro que o handler ou o watcher suposto detectar. No caso dos handlers a informao de controlo tambm indica se o handler baseado em site ou em threads, e se depois do handler ser executado se a operao deve ser tentada de novo.
26
Segurana da implementao uma caracterstica da linguagem no processo de implementao. Protege as computaes e os dados de tentativas de interferncia com o programas compilados (Oz bytecode). As duas aplicaes mais importantes deste nvel de segurana so: na integridade do site e o no controlo de recursos. Os problemas de segurana surgem quando o cdigo passado directa ou indirectamente de um site para outro. Por exemplo, enviado um procedimento para um servidor o executar (directa), ou evocando um mtodo de um objecto mvel (indirecta). A soluo para impedir que o cdigo enviado seja malicioso a implementao de tcnicas de verificao do cdigo bytecode e o uso de autenticao a nvel da compilao. Segurana do sistema operativo e da rede no uma propriedade da linguagem, mas do sistema operativo e da rede. Protegem as computaes e os dados de serem corrompidos por tentativas de interferncia com o emulador de Oz e com o run-time system de um processo do sistema operativo, e tambm tentativas de interferncia com sistema operativo e com a rede. A segurana da rede pode ser conseguida atravs da utilizao de TCP/IP seguro.
27
4. Tutorial de Oz
Neste tutorial ir ser introduzida a linguagem Oz, assim como o seu ambiente de trabalho. O contedo ir incidir sobre as caractersticas fundamentais da linguagem Oz, nomeadamente sobre as caractersticas funcionais, concorrncia, objectos e classes, objectos e concorrncia e programao lgica. Num outro capitulo ir ser abordado o Oz distribudo.
28
A janela inicial est separada em dois buffers. O buffer de cima com o nome de oz, onde escrito o programa que pode ser executado interactivamente. O buffer de baixo contm as mensagens do compilador. Para trabalhar com o Emacs aconselhvel a leitura de um tutorial desta ferramenta.
Isto nada mais, que a invocao de um procedimento em Oz, isto , a chaveta significa que se vai chamar o procedimento Show com o argumento Ol mundo. Para se poder executar este primeiro programa, basta ir ao menu Oz no Emacs e escolher feed line para que o compilador compile a linha.
No buffer do compilador aparece uma mensagem que indica que a linha compilada foi aceite pelo compilador. Embora possa parecer estranho no termos nenhum resultado aparente, mas o que se passa efectivamente que o resultado encontra-se noutro buffer chamado Oz Emulator. Se escolhermos a opo do menu Oz Show Hide e de seguida Emulator, veremos o resultado.
29
Ctr +l Ctr +r +b
Compila a regio seleccionada Ctr Compila o buffer Compila o pargrafo (limitado por linhas vazias) Ctr Compila o pargrafo
Erros do Compilador O OPI tem mecanismos bastante simples para procurar e indicar os erros de compilao. A melhor maneira de perceber como funciona atravs de um exemplo. Se introduzirmos o seguinte cdigo com erros:
Local A B in A = 3 Proc {B} {Show A + Teste } end {B 7} end
30
Se for primido Ctr + x e de seguida `, o cursor no buffer do programa ir deslocar-se para a posio onde foi detectado o primeiro erro.
31
tomo. Se for primido de novo Ctr + x e depois `, o cursor vai posicionar-se no prximo erro do buffer do programa.
Este erro sucedeu porque o procedimento B no leva argumentos. O Browser O Oz tem bastantes ferramentas grficas de apoio ao desenvolvimento. O browser uma ferramenta que serve para obter uma visualizao dos resultados da execuo de um programa atravs de um interface grfico. Se compilarmos a seguinte linha:
{Browse Ol mundo}
Figura 13 O browser
O browser ir mostrar os nomes das vaiveis porque estas no se encontram instanciadas e no caso da rea ir mostrar _ porque no conhecendo o valor das variveis no pode efectuar o calculo.
32
Finalmente se instanciarmos H com o valor 5, iremos obter o resultado da rea porque a variveis que esse calculo depende esto todas instanciadas.
O browser permite-nos ver a evoluo da instanciao de termos ou variveis ao longo da execuo de computaes concorrentes (threads).
33
Define as variveis lgicas X,Y e Z dentro do espao lxico S. Ou seja S corresponde a um conjunto de instrues onde essas variveis podem ser acedidas. As variveis comeam por uma letra maiscula e seguidas de caracteres alfanumricos. As variveis tambm podem ter a forma de uma string limitada por apstrofos. Imediatamente depois de serem declaradas as variveis no tm nenhum valor associado, dizem-se no instanciadas. Qualquer varivel em Oz deve ser definida antes de ser utilizada excepto, como veremos mais tarde em algumas situaes no pattern matching. Outra forma de definir variveis :
declare X Y Z in S
A diferena est relacionada com a rea de aco das variveis. Em vez de estarem definidas num espao limitado pela palavra chave end, neste caso atravs do declare, as variveis iro ter um alcance global, a no ser que existam blocos que entretanto definam variveis como o mesmo nome.
34
A figura 17, mostra a hierarquia que existe entre os tipos de dados no Oz. Qualquer varivel pode instanciar valores de qualquer dos tipos representados. A maior parte dos tipos so comuns noutras linguagens de programao com a excepto os Chunk, Cell, Space, FDInt e Name. Ao longo deste tutorial iro ser explicados na devida altura. O tipo da varivel determinado quando instanciada, isto , dependendo do valor que se lhe atribuir, assim ser o seu tipo.
Se a varivel X j estivesse instanciada com o valor 1, esta operao seria interpretada com um teste varivel X. Se X fosse instanciada com um valor diferente de 1, seria levantada a excepo correspondente.
4.3.2 Nmeros
O Oz suporta nmeros inteiros e de virgula flutuante. Os inteiros tm um preciso infinita, isto , podem tem um qualquer tamanho. A representao dos valores inteiros pode ser feita utilizando vrias notaes, nomeadamente a notao binria, octal, decimal e hexadecimal. Para representar um octal, nmero deve ser precedido de um O, para representar um hexadecimal o nmero deve ser precedido de 0x. Os caracteres so inteiros entre 0 e 255 e podem ter uma
35
representao sintctica, por exemplo o caracter t pode ser representado por &t, ou nova linha pode ser representado por &\n. Os nmeros de virgula flutuante distinguem-se dos inteiros por terem um ponto decimal. O sinal menos representado por ~. Vejamos alguns exemplos: ~3.141 4.5E3 ~12.0e~2 No Oz no existe converso automtica de tipos, isto , 5.0 = 0 ir levantar uma excepo. Obviamente existem mtodos de converso de tipos para permitir este tipo de comparaes. As operaes sobre nmeros encontram-se no mdulo Number.
4.3.3 Literais
Existem dois tipos de literais: os tomos e os nomes. O tomo um entidade simblica representada por um conjunto de caracteres, em que o primeiro caracter minsculo, ou ento, quaisquer caracteres limitados por apstrofos. Por exemplo:
a foo = := Oz 3.0 Ola Mundo
Os tomos possuem uma ordenao baseada num ordem lexicogrfica. Outro tipo de literais so os nomes. Os nomes consistem em sequncias nicas de caracteres. A criao de um nome feita usando o procedimento {NewName X}, onde X ficar com o nome gerado. Os nomes gerados no podem ser forjados ou visualizados e so normalmente usados para questes relacionadas com segurana. Um subtipo particular dos nomes so os valores booleanos, que consistem em dois nomes protegidos, isto , no podem ser redefinidos e so representados pelas palavras reservadas true e false. O tipo unit tambm um nome, que usado para sincronizao em programao concorrente. O cdigo seguintes mostra a definio destes tipos de dados.
local X Y B in X = foo {NewName Y} B = true {Browse [X Y B]} end
Neste caso o registo tem quatro argumentos e um identificador tree. Cada argumento constitudo pelo par propriedade:campo. No exemplo as propriedades so: chave, valor, esquerda e direita. Os campos so K,V,LT e RT. Se omitirmos as
36
O resultado ser :
[tree(chave:pedro valor:13 esquerda:nil direita:nil) tree(pedro 13 nil nil)]
Grande parte das operaes que podem ser executadas sobre os registos encontram-se no modulo Record. Vejamos agora algumas operaes bsicas que podem ser feitas sobre estas estruturas de dados. Para seleccionar um campo de uma determinada propriedade de um registo usa-se o operador infixo ponto (.). Por exemplo:
{Browse T.chave} % mostra pedro no ecr {Browse W.1} % tambm mostra pedro no ecr
O arity de um registo a lista das suas propriedades ordenadas lexicograficamente. O procedimento {Arity R X} obtm o arity do registo R e colocao na varivel X. Por exemplo:
local X in {Arity T X} {Browse X} end local X in {Arity W X} {Browse X} end
O resultado ser :
[chave valor esquerda direita] % no primeiro caso [1 2 3 4] % no caso do tuplo
Outra operao que pode ser bastante til a seleco condicional de um campo de um registo. O procedimento CondSelect recebe um registo R, a propriedade F, um valor de campo por omisso D e o resultado colocado num ultimo argumento X. Funciona da seguinte maneira: Se a propriedade F existe em R ento X fica com o valor de R.F, seno X fica com o valor de D.
local X in {CondSelect W chave omissao X} {Browse X} end local X in {CondSelect T chave omissao X} {Browse X} end
Na primeira expresso, como no existe a propriedade chave, porque W um tuplo, o resultado ser omissao. Na segunda expresso, o registo T possui uma propriedade chave, ento X fica com o valor da chave que pedro.
37
Um operador bem comum na utilizao dos tuplos o #. Este operador define um tuplo com dois ou mais elementos. Por exemplo a expresso 1#2#3 define o tuplo #(1 2 3). Se desejarmos criar tuplos com um ou sem elementos, devemos defini-lo da forma habitual, ou seja: # (X) para um elemento ou #() para um tuplo sem elementos. A operao {AdjoinAt R1 F X R2} instancia R2 com o registo resultante da adio a R1 da propriedade F e do campo X. Se a propriedade F j existir em R1 em R2 aparecer com o valor de X. A operao {AdjoinList R LP S} recebe um registo R, uma lista de pares propriedade campo, e retorna um novo registo S tal que: o identificador de R o mesmo de S; Todas as propriedades que no existam em R so adicionados a partir da lista LP, caso existam, o valor que ir passar para S ser o que est definido no par propriedade campo na lista LP. Vejamos um exemplo:
local S in {AdjoinList tree(a:1 b:2) [a#3 c#4] S} {Show S} end % O resultado seria S=tree(a:3 b:2 c:4)
4.3.6 Listas
As listas no pertencem a um tipo de dados no Oz. So uma estrutura conceptual. Podem ser representadas de vrias maneiras: o tomo nil representa uma lista vazia; por elementos separados pelo operador | em que o elemento da esquerda a cabea da lista e o da direita a cauda; uma lista fechada pode ser representada entre parnteses recto com os valores separados por espaos; ou pela notao de registos. Vejamos os exemplos:
1|2|3|nil % lista com os valores 1 2 e 3 [1 2 3] % lista fechada com os valores 1 2 e 3 1|2|X % lista com os dois primeiros elementos e X instancia a cauda |(1 |(2 X))
Existe outra notao para um tipo especial de listas que so as cadeias de caracteres ou strings. As strings so representadas por um conjunto de caracteres limitados por aspas. Por exemplo a string:
oz 3.0
convertida na lista:
[79 90 32 51 46 48] ou [&o &z & &3 &. &0]
38
Resulta na string:
123-23 = 100
Nota: Recomenda-se a consulta do manual, pois associado a cada tipo de dados existe um mdulo da linguagem com vrias operaes, entre as quais converses de tipos.
39
Na fuso de dois grafos (Registos), podem existir ciclos. No entanto a operao de fuso guarda informao sobre os pares, aos quais foi feita uma tentativa de fuso anterior, permitindo que a operao seja correctamente executada. Quando uma varivel deixar de ser acessvel os mecanismos de garbage collection iro libertar o n que ela referenciava. Vejamos algumas algumas operaes de igualdade (unificaes) vlidas:
local X Y Z in f(1:X 2:b) = f(a Y) f(Z a) = Z {Browse [X Y Z]} end % O resultado ser [a b R14=f(R14 a)] no browser. % R14 = f(R14 a) um grafo cclico
Nota: Para poder ver a representao finita de Z (grafo cclico), ter de ser seleccionado no Browser, o menu Option, Representation field e depois escolher Minimal Graph.
O prximo exemplo mostra uma operao de igualdade errada:
local X X Y X End Y = = = Z in f(c a) f(Z b) Y
Note-se que a atribuio de c a Z correcta, mas quando tenta atribuir, a a b, levantada um excepo.
Quando se verifica uma igualdade o resultado ser true. Caso no se verifique o resultado ser false. Existe um terceira situao que quando uma varivel no instanciada testada. Neste caso, como a igualdade no pode ser testada, a thread bloqueia at conhecer o valor da varivel. Quando duas estruturas (tuplos, registos) so testadas, pode passar-se o seguinte: Retorna true se os grafos gerados tiverem a mesma estrutura e se cada par propriedade campo corresponder a valores idnticos ou ao mesmo n (unificao).
40
Retorna falso se as estruturas forem distintas ou existir alguma desigualdade nos pares propriedade campo. Suspende a execuo quando faz o teste de um par com outro no instanciado. importante referir que os tipos de dados que foram discutidos at agora possuem igualdade estrutural. Vejamos alguns exemplos:
5 == 5.0 %% retorna false porque numeros de virgula flutuante e inteiros nunca so iguais f(A B) == f(C D) %% retorna true se A==C e B==D
local X Y in {Show f(a {Show f(a {Show f(a {Show f(a end
%% %% %% %%
Apesar da execuo das thrads ser sequencial, existe uma grande diferena das linguagens convencionais. As threads podem ser suspensas, o que significa que por exemplo se a execuo for suspensa na execuo de S1, S2 s ser executada quando forem satisfeitas as necessidades de dados que S1 tem retomando a execuo. Pode acontecer que S2 nem seja executado caso S1 levante uma excepo.
41
A semntica da instruo if a seguinte: Se B for true a instruo S1 executada Se B for false a instruo S2 executada Se B for um valor no booleano levantada uma excepo Se B for uma varivel no instanciada a thread suspende. Os operadores disponveis para fazer comparaes so os seguintes:
== \= =< => > < Igual a Diferente de Menor ou igual a Maior ou igual a Maior que Menor que
Tabela 5 Operadores booleanos
Exemplo:
declare X Y Z X = 5 Y = 10 if X >= Y then Z = X else Z = Y end
Em vez de:
if B1 then S1 else if B2 then S2 else S3 end end
equivalente a:
if B1 then S1 else skip end
42
4.5.3 Procedimentos
Os procedimentos podem ser passados a outros procedimentos ou atribudos a registos ou a variveis (first-class), e so definidos da seguinte maneira:
declare proc {P X1 Xn} S end
Vejamos um exemplo:
declare Max X Y Z proc {Max X Y Z} if X >= Y then Z = X else Z = Y end end X = 5 Y = 10 {Max X Y Z} {Show Z} %% escreve 10
Os procedimentos no retornam valores directamente. Para retornar valores, basta definir como argumentos que iro ser instanciadas dentro do procedimento com os resultados. Quando o procedimento for chamado no lugar desses argumentos colocam-se variveis no instanciadas. Depois de executada a chamada essas variveis iro conter os valores retornados. Por exemplo:
{Max In1 In2 Return}
recomendado usar as convenes do Oz, ou seja, os argumentos que retornam valores devem sempre ser retornados ao fim, e sempre que quisermos definir um procedimento que apenas retorne um valor, devemos usar uma funo em vez de um procedimento.
43
Os procedimentos como so first-class, podem ser atribudos a qualquer entidade do Oz. Para isso utiliza-se uma notao designada de procedimentos annimos. O smbolo $ usado para indicar que um determinado procedimento annimo.
P = proc{$ X1 ... Xn} S end
Neste caso, a varivel P ir ser instanciada com um procedimento. Esta varivel pode ser utilizada da mesma forma que qualquer outra varivel lgica e pode tambm ser utilizada para chamar o procedimento utilizando a forma j conhecida de:
{P X1 ... Xn}
Sendo estas variveis que instanciam procedimentos tratadas de igual modo s outras, podem surgir algumas questes. Por exemplo no que diz respeito ao teste de igualdade. Vejamos um exemplo:
declare proc {Max X Y Z} if X >= Y then Z = X else Z = Y end end proc {Max2 X Y Z} if X >= Y then Z = X else Z = Y end end proc {Min X Y Z} if X >= Y then Z = Y else Z = X end end Alias=Max {Show Max==Min} %% escreve false {Show Max==Max2} %% escreve false {Show Max==Alias} %% escreve true
S a ultima igualdade verdadeira porque a nica que possui igualdade estrutural. Vejamos um exemplo que ilustra como podemos passar directamente o resultado de um procedimento a outro procedimento:
{Show {Max3 1 5 4 $}} %% mostra 5
Se em vez de se colocar uma varivel no instanciada no argumento de retorno, se colocar o smbolo $, o valor automaticamente passado ao procedimento Show. Vejamos agora um exemplo da atribuio de procedimentos a estruturas de
44
dados.
declare fun {Max A B} end fun {Min A B} end MyMathModule=math(max:Max min:Min) declare Max Min {MyMathModule.max 1 3 Max} %% Max=3 {MyMathModule.min 1 3 Min} %% Min=1
Finalmente, um exemplo de uma funo que recebe uma funo (Less) e que retorna uma funo que no programa atribuda a P.
declare fun {GenMax Less} fun{$ A B} if {Less A B} then B else A end end end P={GenMax fun{$ A B} A<B end} {Show {P 5 3}} %%% Shows 5
A varivel P deve ter sido definida anteriormente. A expresso anterior ir dar origem uma expresso lambda seguinte:
45
(X1 Xn).S.
P instanciado com esta abstraco ou clausula que contem o cdigo e referncias s entidades referenciadas pelas variveis livres dentro do procedimento.
A varivel Y definida no primeiro local invisvel dentro da instruo local interior. O resultado que ir resultar ser o seguinte:
[R1=f(R1 2) [1 2]]
Como L igualado a [1 2], a X1 consequentemente atribudo o valor do primeiro elemento de L e a Y o segundo. Logo o tuplo cclico M, ter o seu segundo elemento igualado a 2. Este conjunto de instrues e semelhante a ter:
local Y in Y = 1 local M X1 Y L in M = f(M Y) L = [X1 Y] L = [1 2] {Show [M L]} end end
O smbolo ! pode ser utilizado para suprimir a inicializao de uma varivel. Vejamos o seguinte exemplo:
46
Neste exemplo a inicializao de Y suprimida, logo Y ficar com o valor atribudo no espao lxico exterior, que 1. semelhante a ter :
local Y in Y = 1 local M X1 L in M = f(M Y) L = [X1 Y] L = [1 2] {Show [M L]} end end
Repare-se que neste exemplo, no segundo local no definida a varivel Y, o que significa que o valor que Y ir ter dentro dessa rea, ser o valor que Y tem na rea exterior, ou seja 1.
As variveis introduzidas (que ainda no foram declaradas) nos patterns, tm um espao de aco dentro das respectivas instrues (S1,S2). Imaginemos que E comparado com uma expresso V. A semntica da instruo case a seguinte: A comparao de V com os patterns feita de modo sequencial pela ordem que foram definidos. O teste de comparao de V com um pattern feita de esquerda para a direita e utilizando o critrio do primeiro em profundidade. Se V for comparado com um pattern sem que nenhuma varivel seja instanciada a instruo correspondente ser executada. Se V for comparado com um pattern e apenas algumas das variveis forem instanciadas a thread fica suspensa. Se a comparao de V com um pattern falha, V ser comparado com o prximo pattern, caso todos falhem ser executada a instruo relativa ao else. A parte do else pode ser omitida, mas caso todos os patterns falhem
47
ser levantada uma excepo. Pode ser suprimida a introduo de uma nova varivel local usando o operador ! da seguinte forma:
case f(X1 X2) of f(!Y Z) then ... else ... end
Vejamos este exemplo que consiste num procedimento que serve para introduzir valores numa rvore binria.
proc {Insert Key Value TreeIn ?TreeOut} case TreeIn of nil then TreeOut = tree(Key Value nil nil) [] tree(K1 V1 T1 T2) then if Key == K1 then TreeOut = tree(Key Value T1 T2) elseif Key < K1 then T in TreeOut = tree(K1 V1 T T2) {Insert Key Value T1 T} else T in TreeOut = tree(K1 V1 T1 T) {Insert Key Value T2 T} end end end
48
Como o Oz possui sintaxe para chamar procedimentos dentro de procedimentos, pode-se substituir a seguinte expresso
local Y in {P ... Y ...} {Q Y ... } end
por
{Q {P ... $ ...} ... }
O smbolo $ indica que o valor que est nesse argumento, o valor que passado ao procedimento exterior. No caso do nosso exemplo, o conjunto de chamadas ao procedimento insert poderia ser substitudo por:
{Insert d 7 {Insert c 10 {Insert b 15 {Insert a 3 nil}}}}}
O aninhamento tambm pode ser aplicado a listas, tuplos ou registos. Por exemplo:
Zs = X|{SMerge Xr Ys $}
49
A chamada {And {BinaryTree T1}{BinaryTree T2} B} vai fazer trabalho desnecessrio, isto , atendendo s regras do aninhamento, a segunda expresso vai ser avaliada mesmo que a primeira seja falsa. O que deve ser feito para que isso no suceda definir um procedimento AndThen, que recebe como argumentos dois procedimentos, onde s executa o segundo se o primeiro retornar true. Este processo chama-se Lazy e s possvel porque os procedimentos em Oz, assim como as outras entidades so High-Order.
local proc {AndThen BP1 BP2 ?B} if {BP1} then B = {BP2} else B = false end end in proc {BinaryTree T ?B} case T of nil then B = true [] tree(K V T1 T2) then {AndThen proc{$ B1} {BinaryTree T1 B1} end proc{$ B2} {BinaryTree T2 B2} end B} else B = false end end end
50
J existem definidas em vrios mdulos vrias abstraces de controlo, por exemplo no mdulo Control ou no mdulo List. O facto de os procedimentos em Oz serem High-Order pode ser aproveitado para criar abstraces de controlo. Por exemplo podemos facilmente criar uma abstraco para percorrer todos os elementos de uma lista, aplicando a cada elemento um procedimento P.
proc {ForAll Xs P} case Xs of nil then skip [] X|Xr then {P X} {ForAll Xr P} end end
Onde os iteradores so: X in L itera sobre uma lista L. X in I..J itera sobre os inteiros, de I at J inclusive. X in I..J;K itera sobre os inteiros, de I at J inclusive, com incrementos de K Exemplo:
for X in [1 2 3] do Show end
51
Vejamos um exemplo:
proc {Eval E ?R} case E of plus(X Y) then {Browse X+Y} [] times(X Y) then {Browse X*Y} else raise illFormedExpression(E) end end end
O tratamento de falhas baseado no conjunto de instrues try e catch, e so usadas de forma semelhante a outras linguagens. O sintaxe o seguinte:
try S catch Pattern1 then S1 Pattern2 then S2 Patternn then Sn end
A semntica a seguinte: Se no for levantada nenhuma excepo a instruo S executada normalmente. Se S levanta uma excepo, essa excepo comparada com os pattens. Se alguma dessas comparaes for verificada executada a instruo correspondente. Se a comparao com os patterns no se verificar, a excepo e propagada para fora da instruo try catch e eventualmente tratada pelo sistema Exemplo:
52
try {ForAll [plus(5 10) times(6 11) min(7 10)] Eval} catch illFormedExpression(X) then {Browse ** X **} end
Na conjunto try catch tambm podemos garantir que uma determinada instruo seja executada sendo ou no sendo levantada uma excepo. Isto pode ser feito atravs da palavra finally, que depois de ser executada a instruo correspondente a excepo levantada, ou se nenhuma excepo for levantada, depois de ser executada a instruo sob a palavra try, ser executada a instruo indicada a seguir a esta palavra.
try S catch Pattern1 then S1 Pattern2 then S2 Patternn then Sn finally Sfinal end
Vejamos um exemplo: Assumindo que F um ficheiro aberto, o procedimento Process/1 manipula o ficheiro e o procedimento CloseFile/1 fecha o ficheiro. Este programa garante que o ficheiro seja fechado quer seja ou no levantada uma excepo.
try {Process F} catch illFormedExpression(X) then {Browse ** X **} finally {CloseFile F} end
53
proc {One X} X=1 end proc {Two X} X=2 end try {One}={Two} catch failure(...) then {Show caughtFailure} end
O pattern failure(...) ir capturar qualquer excepo cujo identificador seja failure. A excepo no tratada, apenas escrita no emulator-buffer a mensagem de erro correspondente e depois termina a execuo. Numa aplicao compilada a mensagem aparecer no standard error e depois termina a execuo. Este comportamento pode ser alterado para algo mais desejvel para algumas aplicaes, por exemplo para aplicaes com tolerncia a falhas.
Os mdulos so componentes de software first-class que consistem num conjunto de entidades Oz (procedimentos, objectos, e outros valores) que so agrupados para disponibilizar certas funcionalidades. Um mdulo constitudo por um conjunto de entidades privadas, isto , que no so visveis do exterior, e por um interface que possibilita o acesso s funcionalidades do mdulo. O lexical scoping e certas estruturas de dados como por exemplo os registos facilitam a construo destes componentes.
declare local proc proc proc proc in List List {Append ... } ... end {Partition ... } ... end {Sort ... } ... {Partition ...} ... end {Member ...} ... end = 'export'(append: Append sort: Sort member: Member ... )
end
Outra forma de criar mdulos usando functors. Os functors especificam a criao de um mdulo partindo de outros mdulos (import), especificando o seu interface (export), e a definio das suas funcionalidades (define). O functor correspondente ao exemplo anterior seria:
functor export append:Append sort:Sort member:Member define proc {Append ... } ... end proc {Partition ...} ... end proc {Sort ... } ... {Partition ...} ... end
54
proc {Member ...} ... end end % guardado em /home/person/List.oz % compilado no ficheiro /home/person/List.ozf
Os mdulos podem ser construdos a partir dos functors atravs da seguinte expresso:
declare [List]= {Module.link [/home/person/list.ozf]}
Quando o functor referenciado so executadas as instrues entre o define e o end. Como j foi dito anteriormente podem-se criar functors partindo de outros functors. Para importar os functors basta usar a palavra chave import na definio do functor da seguinte maneira:
functor import Browser FO at 'file:///home/person/FileOperations.ozf' define {Browser.browse {FO.countLines '/etc/passwd'}} end
55
4.8 Concorrncia
Como j foi dito anteriormente, existe uma rea de armazenamento onde toda a informao guardada monotnicamente, isto , apenas adicionada. As threads adicionam informao a esta rea atravs da operao tell e testam a informao atravs da operao ask. Quando as threads testam a informao podem ficar suspensas. Depois de serem lanadas, as thrads alternam entre os estados de execuo e suspenso um numero arbitrrio de vezes at terminarem. Conceptualmente a rea de armazenamento est sempre a crescer, mas existem mecanismos de garbage collection (recolha de lixo), que removem a informao que deixou de ser acessvel. Em Oz uma thread pode ser lanada da seguinte maneira:
Thread S end
As threads so executadas de forma concorrente. Todas as threads em execuo que no esto bloqueadas -lhes eventualmente alocada um tempo de processamento. Isto significa que as threads so executadas de modo fair (justo). Cada thread uma thread de fluxo de dados (dataflow), o que significa que bloqueiam quando tm necessidade de dados.
declare X0 X1 X2 X3 in thread local Y0 Y1 Y2 Y3 in {Browse [Y0 Y1 Y2 Y3]} Y0 = X0+1 % inicialmente a thread suspende aqui Y1 = X1+Y0 Y2 = X2+Y1 Y3 = X3+Y2 {Browse completed} end end {Browse [X0 X1 X2 X3]}
A thread ir suspender na linhas seguinte medida que as suas necessidades de dados vo sendo preenchidas. Vejamos agora um exemplo:
fun {Map Xs F} case Xs of nil then nil [] X|Xr then thread {F X} end |{Map Xr F} end end
56
proc {Map Xs F Rs} case Xs of nil then Rs = nil [] X|Xr then R Rr in Rs = R|Rr thread R = {F X} end Rr = {Map Xr F} end
Uma thread executando a funo Map ser criada, mas como a varivel X no est instanciada a thread ser imediatamente suspensa. Se escrevermos :
X = 1|2|Y fun {F X} X*X end
X ser instanciado com a lista [1 2 Y] e F com a funo X*X. Os requisitos da thread encontram-se satisfeitos e sero criadas duas novas threads para os dois primeiros elementos da lista. Como o terceiro valor da lista no est instanciado a nova thread suspende. Se escrevermos:
Y = 3|Z Z = nil
Por fim todas as necessidades de informao das threads so completadas, retomando a execuo. O resultado ser a lista [1 4 9]. O Programa que se segue, uma forma muito ineficiente de calcular sries de Fibonacci, pois cria um nmero exponencial de threads. No entanto pode ser til para verificar o nmero de thread suportados pelo sistema. Por exemplo pode-se tentar:
{Fib 20}
Se continuar a funcionar deve tentar-se um valor maior que 20. Entretanto deve ser executado o programa panel, que pode ser acedido pelo menu Oz do OPI. O objectivo determinar o limite de threads que o sistema suporta, para que os programas concorrentes possam ser planeados de uma forma mais modular.
fun {Fib X} case X of 0 then 1 [] 1 then 1 else thread {Fib X-1} end end
57
Figura 19 O Oz panel
4.8.1 Tempo
O Oz implementa algumas funcionalidades de soft real-time. Destacam-se os procedimentos: {Alarm I ?U} cria imediatamente a sua prpria thread e instancia U com unit depois de I milisegundos. {Delay I } suspende a execuo da thread por pelo menos I milisegundos.
local proc {Ping N} if N==0 then {Browse 'ping terminated'} else {Delay 500} {Browse ping} {Ping N-1} end end proc {Pong N} {For 1 N 1 proc {$ I} {Delay 600} {Browse pong} end } {Browse 'pong terminated'} end in {Browse 'game started'} thread {Ping 50} end thread {Pong 50} end end
58
fun {Generator N} if N > 0 then N|{Generator N-1} else nil end end local fun {Sum1 L A} case L of nil then A [] X|Xs then {Sum1 Xs A+X} end end in fun {Sum L} {Sum1 L 0} end end local L in thread L = {Generator 150000} end {Browse {Sum L}} end
Este programa gera uma lista com os valores menores que um determinado nmero (150000) e soma-os. O resultado dever ser 11250075000. Um produtor vai incrementado um stream (lista), isto feito de uma forma eager, ou seja :
fun {Producer ...} ... volvo|{Producer ...} ... end
Por causa do comportamento dependente do fluxo de dados enquanto no chegar a stream o prximo elemento o consumidor fica suspenso. A chamada recursiva permite o consumidor repetir o processo. No exemplo seguinte cada vez que o consumidor recebe mil automveis escreve uma mensagem.
fun {Producer N} if N > 0 then volvo|{Producer N-1} else nil end end proc {Consumer Ls} proc {Consumer Ls N} case Ls of nil then skip [] volvo|Lr then if N mod 1000 == 0 then {Browse driving a new volvo'} end {Consumer Lr N+1} else {Consumer Lr N} end end in {Consumer Ls 1} end
59
O procedimento:
{Property.put priorities(high:X medium:Y)}
Ir colocar o racio temporal do processador em X:1 entre threads de alta prioridade e mdia prioridade, e ir tambm colocar o racio Y:1 entre as threads de mdia prioridade e baixa prioridade. X e Y so valores inteiros. Por exemplo:
{Property.put priorities(high:10 medium:10)}
Aplicando isto ao programa produtor-consumidor, poderemos resolver o problema da utilizao dos buffers. Esta expresso estabelece que as racios so 10:1 entre a alta prioridade a mdia e 10:1 entre a mdia e a baixa.
60
E consumidor seria:
proc {Consumer ... Xs} X Xr in ... Xs = X|Xr Consume X ... {Consumer ... Xr} end
61
else {Consumer N Xs} end end end in {Consumer 10000000 thread {Producer $} end} end
Existe ainda outra maneira de resolver o problema. Existe outra forma de executar computaes orientadas ao pedido, atravs do uso de futures e da primitiva ByNeed. Uma future consiste na propriedade de leitura de uma varivel. Para criar a future da varivel X usa-se o smbolo !! e atribuda a Y.
Y = !!X
Uma thread quando tenta usar o valor da future, suspende at que a varivel da future seja instanciada. Pode-se executar um procedimento orientado ao pedido atravs da operao {ByNeed +P ?F}. Esta operao recebe um procedimento e retorna uma future F. Quando uma thread tenta aceder ao valor de F, o procedimento {P X} chamado e o seu resultado X atribudo a F. Por exemplo:
declare Y {ByNeed proc($ X) X = 1 end Y} {Browse Y}
O Y passa a ser uma future e ir ser instanciada com o valor 1. Outra maneira de aceder a Y, esperando que Y tenha um valor atravs da operao {Wait Y}. Vejamos o exemplo do Volvo usando ByNeed:
local proc {Producer Xs} Xr in Xs = volvo|{ByNeed {Producer Xr} $} end end proc {Consumer N Xs} if N>0 then case Xs of X|Xr then if X==valvo then if N mod 1000 == 0 then {Browse 'riding a new volvo'} end end {Consumer N-1 Xr} else {Consumer N Xr} end end end in {Consumer 10000000 thread {Producer $} end} end
62
Isto uma situao particular da deteco de terminao de threads e ter outra thread espera desse evento. Mais uma vez, sendo o Oz uma linguagem dependente do fluxo dos dados, isto pode ser feito de forma bastante simples.
thread T1 X1 = unit end thread T2 X2 = X1 end ... thread TN XN = XN-1 end {Wait XN} MainThread
Quando as threads terminam as variveis X1,X2,...,Xn so fundidas contendo o valor unit. A operao {Wait Xn} espera que a varivel Xn seja instanciada, ou seja indica que a ultima thread da sequncia foi terminada.
63
4.9.1 Ports
Os ports so canais de comunicao assncronos que podem ser partilhados por vrios emissores. Os ports tm sempre um stream associado. A operao {Port.new S ?P} cria um port P e associa-o a um stream S. A operao {Port.send P M} acrescenta no fim do stream associado a P a mensagem M. As inseres nos ports so sempre feitas no fim. A operao {Port.is P ?B} verifica se P um port. Para proteger o stream S de ser instanciado outra vez, S e uma future. A semntica a seguinte: As mensagens enviadas pela mesma thread chegam com a ordem de envio, mas mensagens enviadas por threads diferentes podem chegar com uma ordem arbitraria.
64
Executando este cdigo, verificamos que S est sempre a crescer. O resultado produzido ser:
S<Future> 1|_<Future> 1|2|_<Future>
Os ports so abstraces mais expressivas que a comunicao de streams pura, pois podem ser partilhados por vrias threads e podem ser embebidos noutras estruturas de dados. Os ports so o principal mecanismo para comunicao entre threads existente no Oz. Relativamente thread, a ordenao das mensagens do tipo FIFO. Vejamos o seguinte exemplo:
declare S P P = {Port.new S} {Browse S} thread ... {Port.send P a1} ... {Port.send P a2} end ... {Port.send P b1} ... {Port.send P b2}
65
Given GivePort={Port.new Given} Taken TakePort={Port.new Taken} in thread Given=Taken end queue(put:proc{$ X} {Port.send GivePort X} end get:proc{$ X} {Port.send TakePort X} end) end
Ou alternativamente:
declare functor NewQueueServer export put: proc {$ X} {Port.send GivePort X} end get: proc {$ X} {Port.send TakePort X} end define Given GivePort={Port.new Given} Taken TakePort={Port.new Taken} thread Given = Taken end end
= TakePort
X1=E1 X2=E2
X1 X2 <Future 2>
O programa funciona da seguinte maneira: {Q.put I0} {Q.put I1} ...{Q.put In} adiciona os elementos I0, I1, ..., In ao stream Given. O resultado I0|I1|...|In <future1>. {Q.get X0} {Q.get X1} ... {Q.get Xn} ir adicionar os elementos X0 , X1, ..., Xn ao stream Taken. O resultado o stream X0|X1|...|Xn <future2>. A igualdade Given = Taken ir instanciar os Xi com os Ii.
4.9.3 As clulas
As clulas (cells) referenciam uma clula de memria que tem um componente mutvel. Funcionam como as variveis nas linguagens convencionais. O procedimento {NewCell X ?C} cria uma clula com o valor inicial X. C instanciado com a Clula.
66
O exemplo que se segue faz uso de clulas e iteradores high-order para acumular o valor de uma clula.
declare C = {NewCell 0} {For 1 10 1 proc {$ I} O N in {Exchange C O N} N = O+I end} {Browse {Access C}} %% o resultado ser 55
4.9.4 Chunks
Os chunks so estruturas semelhantes aos registos s que: O identificador do chunk um nome Oz e no existe operao de arity sobre os chunks. Isto permite que certos componentes do chunk possam ser escondidos se uma propriedade do chunk um nome Oz que apenas visvel atravs do lexical scoping, por operaes definidas pelo utilizador sobre o chunk. Um chunk pode ser criado da seguinte maneira:
{NewChunk Record ?Chunk}
Esta expresso cria um chunk com a mesma estrutura do registo mas com um identificador nico.
local X in {Browse X={NewChunk f(c:3 a:1 b:2)}} {Browse X.c} end
Os chunks e as clulas so tipos de dados primitivos do Oz, isto , todos os outros tipos de dados que representam estados existentes no Oz, podem ser construdos com base nestes dois tipos.
67
4.9.5 Locks
Os locks so os mecanismos existentes em Oz para garantir acesso exclusivo a seces criticas, que correspondem a uma zona de cdigo Oz. Quando uma thread entra numa seco critica, o lock activado e garantido o acesso exclusivo da thread ao recurso. Quando a execuo abandona a regio correspondente seco critica, quer na sequncia normal de execuo, que por interveno de uma excepo, o lock libertado. Uma thread que concorra para obter um lock que est ocupado, bloqueia at que o esse lock seja libertado. Os locks so reentrantes como no java. Os locks no so primitivos do Oz, isto , podem ser implementados atravs de clulas. Para aplicar um lock a uma seco critica S, faz-se o seguinte:
lock L then S end
O L a expresso associada ao lock. Assumindo que T uma thread que executa a expresso anterior, se L estiver livre, T executa S e L fica ocupado. Se L estiver ocupado, T bloqueia e fica no fim da fila aguardando a sua vez para ocupar L. Todas as outras threads bloqueiam enquanto uma thread executar S. Existem as seguintes operaes sobre locks:
{Lock.new ?L} cria um novo lock L . {Lock.is E} devolve true se E for um lock.
Para os locks simples a reentrncia no suportada. Isto , se a mesma thread tentar readquirir o lock bloqueia. O locks simples podem ser implementados atravs do seguinte cdigo:
proc {NewSimpleLock ?Lock} Cell = {NewCell unit} in proc {Lock Code} Old New in try {Exchange Cell Old New} {Wait Old} {Code} finally New=unit end end end
Code um procedimento sem argumentos que corresponde seco critica. O lock representado sob a forma dum procedimento, que quando aplicado ao code, tenta deter o lock esperando que a varivel Old seja instanciada com unit. Note-se que o lock libertado quando a execuo de code termina de forma normal ou por meio de uma excepo.
68
69
4.10.3 As Classes em Oz
O Oz implementa programao orientada a objectos utilizando as metodologias vistas anteriormente, mas possui no seu sintaxe vocabulrio especifico e a nvel da implementao, possui certas optimizaes para que a invocao de mtodos em objectos, tenha o mesmo desempenho que a simples chamada a um procedimento. A classe Counter definida anteriormente poderia ser rescrita sobre a forma:
class Counter attr val meth browse {Browse @val} end meth inc(Value) val <- @val + Value end meth init(Value) val <- Value end end
70
A expresso E um registo que especifica a cabea do mtodo e consiste num registo cujo identificador corresponde ao nome do mtodo.Para se aceder a um atributo A usa-se @A. Para atribuir um valor a um atributo A usa-se A <- E. Uma classe pode ser annima como os procedimentos. Define-se da seguinte forma:
X = class $ ... end
O exemplo a seguir mostra como um objecto pode ser criado a partir de uma classe usando o procedimento New/3, cujo primeiro argumento a classe, o segundo o mtodo inicial, e o terceiro o resultado, isto , o objecto. O procedimento New o procedimento genrico de criao de objectos a partir de classes.
declare C = {New Counter init(0)} {C browse} {C inc(1)} {C browse}
Uma chamada esttica a um mtodo s pode ser usada no interior da definio da classe. A chamada ao mtodo recebe o prprio objecto denominado de self como argumento implcito. O mtodo m pode estar definido na classe C ou numa classe de hierarquia superior (super classe). Vejamos um exemplo:
declare functor ListF export append:Append member:MemberB length:Length define class ListClass from BaseObject meth append(Xs Ys $) case Xs of nil then Ys [] X|Xr then X|(ListClass , append(Xr Ys $))
71
end end meth member(X L $) end meth length(Xs $) end O = {New ListClass noop} fun {Append X Y} {O append(X Y $)} end fun {MemberB X L} {O member(X L $)} end fun {Length L} {O length(L $)} end end
Este exemplo bastante interessante, porque para alm de demonstrar a utilizao de chamadas estticas a mtodos, tambm demonstra como as classes podem ser usadas como especificaes de mdulos, isto , a classe ListC define procedimentos comuns de tratamento de listas como mtodos. Para alm disso tambm se pode ver um exemplo de herana de classe em Oz atravs da expresso :
class ListClass from BaseObject
Extenso conservadora:
class VerboseAccount from Account meth verboseTransfer(Amount) {self transfer(Amount)} {Show @balance} end end
Extenso no conservadora:
class AccountWithFee from VerboseAccount attr fee:5 meth transfer(Amount) VerboseAccount,transfer(Amount-@fee) end end
72
As classes podem herdar de uma ou vrias classes definidas depois da palavra chave from. A classe B uma superclasse de A se: B aparece depois de from na declarao da classe A, ou B uma superclasse de uma classe que aparece depois da palavra chave from na declarao de A. Os mtodos (atributos e propriedades) disponveis (visveis) na classe C esto definidos segundo uma relao de precedncia sobre os mtodos sobre os mtodos que aparecem na hierarquia da classe: relao de sobrecarga: Um mtodo na classe C sobrecarrega um qualquer mtodo de uma superclasse, se esse mtodo tiver o mesmo identificador que o do mtodo da superclasse. Para a herana de classes ser vlida no pode haver relaes cclicas entre as classes.
4.10.6 Propriedades
As propriedades so componentes das classes e so especificados da seguinte forma:
class C from feat a1 an end
Tal como nos registos, as propriedades dos objectos tm um campo associado. Esse campo consiste num varivel lgica que pode ser instanciada com qualquer valor Oz, isto , com clulas, registos, objectos, classes, etc... Para se aceder ao valor da propriedades usa-se o operador infixo ..
class ApartmentC from BaseObject meth init skip end end class AptC from ApartmentC feat streetName: york streetNumber:100 wallColor:white floorSurface:wood end Apt = {New AptC init} {Browse Apt.streetName}
73
As propriedades so inicializadas na altura da definio da classe: Todas as instancias da classe iro ter as propriedades com os valores definidos na classe. No exemplo que se segue ir ser escrito o nome york duas vezes.
declare Apt1 Apt2 Apt1 = {New AptC init} Apt2 = {New AptC init} {Browse Apt1.streetName} {Browse Apt2.streetName}
Propriedades no instanciadas:
class MyAptC1 from ApartmentC feat streetName end
Quando uma instancia de uma classe criada, o campo da propriedade no instanciada uma nova varivel. Exemplo:
declare Apt3 Apt4 Apt3 = {New MyAptC1 init} Apt4 = {New MyAptC1 init} Apt3.streetName = kungsgatan Apt4.streetName = sturegatan
Neste exemplo a propriedade streetName do objecto Apt3 instanciado com com o tomo kungsgatan e a propriedade streetName do objecto Apt4 instanciada com o tomo sturegatan. Quando as propriedades so instanciadas com um valor Oz, por exemplo uma varivel, todas as instancias iro partilhar a mesma varivel.
class MyAptC1 from ApartmentC feat streetName:f(_) end declare Apt1 Apt2 Apt1 = {New MyAptC1 init} Apt2 = {New MyAptC1 init} {Browse Apt1.streetName} {Browse Apt2.streetName} Apt1.streetName = f(york)
Neste exemplo a propriedade streetName de Apt2 ir ter o mesmo valor de streetName de Apt1.
74
Podemos criar uma classe com os operadores. Por exemplo para inteiros e racionais:
class Int meth less(X Y $) X<Y end end class Rat from Object meth less(X Y $) /(P Q) = X /(R S) = Y in P*S < Q*R end end
75
Para inteiros:
{Browse {{New {SortClass Int} noop} qsort([1 2 5 3 4] $)}}
Para racionais:
{Browse {{New {SortClass Rat} noop} qsort([/(23 3) /(34 11) /(47 17)] $)}}
O mtodo A(X) apenas visvel do interior da classe. Esta notao representada de uma forma mais primitiva da seguinte forma:
local A = {NewName} in class C from meth !A(X) end meth a(){self A(5)} end end end
Muitas das linguagens de programao orientada a objectos tambm possuem o conceito de mtodos protegidos. Um mtodo protegido consiste num mtodo que apenas acessvel na classe onde est definido, ou nas classes descendentes. Como os atributos apenas so visveis dentro da prpria classe ou nas classes descendentes, para criar mtodos protegidos basta em primeiro lugar tornar os mtodos privados e depois guarda-los em atributos.
local ProtMeth in {NewName ProtMeth} class C2 attr protMeth:ProtMeth meth !ProtMeth ... end meth otherMethod {self @protMeth} end end end
76
Se for criada uma classe C2 descendente de C1, o mtodo protegido pode ser chamado da seguinte forma:
class C1 from C meth b(...) L=@protMeth in {self L(5)} ... end ... end
Para este exemplo, se as propriedades d1 e d2 no forem especificadas estes argumentos iro ter o valor 0. Vejamos um exemplo que ilustra alguns dos conceitos aprendidos at agora sobre objectos:
class BoundedPoint from Point attr xbounds: 0#0 ybounds: 0#0 boundConstraint: BoundConstraint meth init(X Y xbounds:XB <= 0#10 ybounds:YB <= 0#10) Point,init(X Y) % call your super xbounds <- XB ybounds <- YB end meth move(X Y) if {self BoundConstraint(X Y $)} then Point,move(X Y) end end meth BoundConstraint(X Y $) (X >= @xbounds.1 andthen X =< @xbounds.2 andthen Y >= @ybounds.1 andthen Y =< @ybounds.2 ) end meth display Point,display {self DisplayBounds} end meth DisplayBounds X0#X1 = @xbounds Y0#Y1 = @ybounds S = "xbounds=("#X0#","#X1#"),ybounds=(" #Y0#","#Y1#")" in {Browse S} end end
77
Esta operao semelhante operao Exchange aplicada s clulas, isto , efectua trocas atmicas em atributos de objectos.
class SimpleLock attr lck: unit meth init skip end meth lock( Code) Old New in try Old = lck <- New {Wait Old} {Code} finally New= unit end end end
78
class ReentrantLock from SimpleLock attr Current: unit meth lck( Code) ThisThread = {Thread. this} in case ThisThread == @Current then {Code} else try Code1 = proc {$} Current <- ThisThread {Code} end in SimpleLock, lck{ Code1} finally Current <- unit end end end end
Podemos declarar na classe que os seus objectos possuem um lock por omisso quando estes so criados. Uma classe com a declarao implcita de um lock feita da seguinte forma:
class C from .... prop locking .... end
Isto no fecha automaticamente o objecto quando um dos seus mtodos invocado, tem de ser usada a expresso
lock S end
dentro do mtodo para seja garantido o acesso exclusivo quando S executado. importante relembrar que os locks so de threads reentrantes, isto significa que: Se em todos os objectos que construmos colocarmos lock S end em todos os mtodos e executarmos o programa com apenas uma thread, ter de ter o mesmo comportamento que antes. Vejamos agora um exemplo de como pode refinar uma classe para poder ser usada de forma concorrente:
class Counter attr val meth browse {Browse @val} end meth inc(Value) val <- @val + Value end meth init(Value) val <- Value end
79
end
class CCounter from Counter prop locking meth inc(Value) lock Counter,inc(Value) end end meth init(Value) lock Counter,init(Value) end end end
4.11.6 Eventos
A classe seguinte define a noo e operaes de evento (notify(Event) e wait(Event) ) atravs da classe Channel.
class Event from Channel meth wait Channel , get(_) end meth notify Channel , put(unit) end end
80
Vejamos o exemplo do unit buffer. O comportamento bastante semelhante ao do canal FIFO relativamente s threads consumidoras. Cada thread consumidora espera que o buffer esteja cheio. Relativamente s threads produtoras, apenas uma pode inserir um item no buffer vazio. As outras threads produtoras ficam suspensas, at que, o elemento seja consumido. Veja-se que no necessrio utilizar locks directamente neste programa. A combinao de variveis lgicas com objectos tornam bastante simples e clara, a programao de problemas deste tipo.
class UnitBuffer from BaseObject attr prodq buffer meth init buffer <- {New Channel init} prodq <- {New Event init} {@ prodq notify} % Buffer est vazio end meth put(I) {@ prodq wait} {@ buffer put(I)} end meth get(?I) {@ buffer get(I)} {@ prodq notify} end end
Se quisermos um tamanho varivel do buffer podemos pass-lo como argumento ao mtodo init e modificar da seguinte maneira este mtodo: Criar um ciclo que mande N notificaes de buffer livre.
class BoundedBuffer from UnitBuffer attr prodq buffer meth init( N) buffer <- {New Channel init} prodq <- {New Event init} {For 1 N 1 proc {$ _} {@ prodq notify} end} end end
81
por ultimo uma thread que trata as mensagens recebidas no port, chamando o mtodo correspondente.
fun {NewServer Class init} S % O stream do port Port = {NewPort S} Object = {New Class init} in thread {ForAll S proc{$ M} {Object M} end} end Port End
No prximo exemplo adicionou-se a possibilidade de terminar a thread construindo um mtodo protegido close que acessvel aos mtodos da classe. Para saltar fora do ciclo de recepo de mensagens, usa-se um mecanismo baseado em tratamento de excepes.
local CloseException = {NewName} class Server attr close: Close meth Close raise CloseException end end end in fun {NewServer Class init} S % O stream do port Port = {NewPort S} Object = {New class $ from Server Class end init} in thread try {ForAll S proc{$ M} {Object M} end} catch !CloseException then skip end end Port end end
82
Cria um array de 100 elementos, indexado de 1 a 100 e inicializado a nil. Para se inserir um elemento no array basta fazer:
{Array.put Arr 1 a} ou Arr.1:=a
A expresso seguinte cria um registo (tuplo) que a cpia sem ser baseada em estados do array.
R={Array.toRecord +Label +Array}
Um dicionrio uma estrutura de dados parecida aos arrays onde existe uma associao entre chaves e entradas. Pode ser criado da seguinte forma:
Dict={NewDict}
A prxima expresso idntica anterior, caso exista uma entrada para essa chave, caso contrrio devolve um valor por omisso.
X={Dictionary.condGet Dict Chave Default}
Finalmente a expresso seguinte cria uma cpia do dicionario sob a forma de tuplo:
R={Dictionary.toRecord +Label +Dict}
83
84
Uma condio C vinculada ao armazenamento se C, for uma formula lgica e estiver implcita no armazenamento . Isto , adicionando C ao armazenamento no acrescenta informao ao que j l existe. Uma condio C desvinculada ao armazenamento se uma contradio de C estiver existir no armazenamento . Uma restrio desvinculada inconsistente com a informao que j existe no armazenamento. Sendo o armazenamento de restries uma formula lgica, pode tambm falar-se em vincular um armazenamento de restries a outro. Por exemplo, se considerarmos o armazenamento = X=1 e ... e Y=f(X Z) e as seguintes condies: X=1 vinculado porque esta atribuio no acrescenta informao ao espao . Existe pelo menos um U tal que Y=f(1 U), esta condio tambm vinculada porque no adiciona informao ao armazenamento. J existe uma condio X=1 e independentemente do valor que Z venha a ter a condio satisfeita. Y=f(1 2) no vinculado porque esta condio ir aumentar informao existente no armazenamento, nomeadamente a informao Z=1. X=2 e Y=f(3 U) ambas so desvinculadas do armazenamento , porque contradizem a informao l existente. Isto , X=2 contradiz X=1 e Y=f(3 U) tambm contradiz X=1. Ser levantada uma excepo, que no nvel superior aparecer ao utilizador sobre a forma de mensagem de erro.
4.13.4 Disjunes
Em Oz as disjunes so especificada usando a instruo or. As expresses disjuntivas so expressas na forma de clausulas. Uma clausula composta por um guarda G e por corpo S1.
or G1 then S1 [] G2 then S2 . [] GN then SN end
Assumindo que executa numa thread num espao SP, a semntica da instruo or a seguinte: A thread bloqueia. So criados N espaos SP1, SP2, ..., SPn com uma thread associada a cada executando cada um dos guardas G1, G2, ..., Gn. A execuo da thread principal fica bloqueada at que pelo menos um dos espaos computacionais filhos no falhe. Se todos os espaos filhos falharem a thread pai levantada uma
85
condio de falha no seu espao. Se o espao da thread for o topo da hierarquia de espaos, levantada uma excepo. Caso no seja o topo, simplesmente fica um espao falhado. Se restar um espao que no tenha falhado fundido com o espao pai. A execuo da thread inicial retomada executando o corpo da clausula correspondente ao guarda associado ao espao que no falhou. Pode abreviar-se a seguinte expresso:
or ... [] Gi then skip ... end
da seguinte forma:
or ... [] Gi ... end
A instruo or no introduz o conceito de no determinismo. No prolog no existe uma instruo correspondente ao or. O disjuntor P ; Q cria um ponto de escolha sujeito a backtraking.
86
conhecido, porque no consegue escolher uma disjuno. De forma similar Sum3 ir esperar que S seja conhecido. Como o S criado incrementalmente o comportamento de Sum3 ser uma secesso de suspenses e execues. O programa comea realmente a funcionar quando N instanciado com o valor 1000.
Assumindo que a thread executa num espao SP, esta instruo tem a seguinte semntica: A thread fica bloqueada. Um espao computacional SP1 criado com uma s thread que executa o guarda cond X1 ... XN in S. A execuo da thread pai fica suspensa at que SP1 seja vinculado ou desvinculado. Estas condies podem nunca ocorrer, por exemplo, se existir uma thread suspensa ou se existir uma thread em execuo permanente. Se a SP1 for desvinculado a thread pai continua com a execuo de S2. Se SP1 for vinculado, fundido com com SP e a thread pai continua com a execuo de S1. A instruo cond parecida com as expresses condicionais do Prolog ( P->Q ; R ). O Oz um pouco mais cuidadoso no espao de abrangncia das variveis, tendo que ser declaradas explicitamente.
Uma expresso condicional paralela e executada avaliando todas as condies G1, G2, ..., G(N-1), de forma arbitraria e concorrente, em que cada thread tem o seu prprio espao. Se o espao Gi for vinculado, a instruo Si escolhida pela thread pai. Se todas os espaos falharem, a instruo SN escolhida. Em caso contrrio a thread fica suspensa.
87
Um exemplo tipico de programao lgica concorrente a fuso binria. A fuso binria consiste um fundir dois streams, em que a ordem de chegada dos elementos dos dois streams determinam a ordem em que estaro na lista resultante.
proc {Merge Xs Ys Zs} cond Xs = nil then Zs = Ys [] Ys = nil then Zs = Xr [] X Xr in Xs = X|Xr then Zs = X|Zr {Merge Xr [] Y Yr in Ys = Y|Yr then Zs = Y|Zr {Merge Xs end end
Zr Ys Zr Yr
in Zr} in Zr}
Normalmente a fuso binria ineficiente. Uma maneira mais eficiente usando clulas e streams.
proc {MMerge STs L} C = {NewCell L} proc {MM STs S E} case STs of ST|STr then M in thread {ForAll ST proc{$ X} ST1 in {Exchange C X|ST1 ST1} end} M=S end {MM STr M E} [] nil then skip [] merge(STs1 STs2) then M in thread {MM STs1 S M} end {MM STs2 M E} end end in thread {MM STs unit E} end thread if E==unit then L = nil end end end
88
proc {Append Xs Ys Zs} dis Xs = nil Ys = Zs then skip [] X Xr Zr in Xs = X|Xr Zs = X|Zr then {Append Xr Ys Zr} end end
Neste caso o comportamento ser igual ao da instruo or, isto , X ser instanciado deterministicamente com a lista [1 2 3 a b c]. Mas se for chamado na forma:
local X Y in {Append X Y [1 2 3 a b c]} {Browse X#Y} end
O comportamento semelhante instruo or. A thread bloqueia quando tenta executar {Append X Y [1 2 3 a b c]}. No entanto existe um diferena que reside criar um ponto de escolha com duas alternativas: X = nil Y = [1 2 3 a b c] then skip Xr Xr in X = 1|Xr Zr = [2 3 a b c] then {Append Xr Y Zr}
89
4.13.10 Exemplos
Definio de uma gramtica:
Sentence(P) --> NounPhrase(X P1 P) VerbPhrase(X P1) NounPhrase(X P1 P) --> Determiner(X P2 P1 P) Noun(X P3) RelClause(X P3 P2) NounPhrase(X P P) --> Name(X) VerbPhrase(X P) --> TransVerb(X Y P1) NounPhrase(Y P1 P) | InstransVerb(X P) RelClause(X P1 and(P1 P2)) --> [that] VerbPhrase(X P2) RelClause(_ P P) --> [] Determiner(X P1 P2 all(X imp(P1 P2))) --> [every] Determiner(X P1 P2 exits(X and(P1 P2))) --> [a] Noun(X man(X)) --> [man] Noun(X woman(X)) --> [woman] name(john) --> [john] name(jan) --> [jan] TransVerb(X Y loves(X Y)) --> [loves] IntransVerb(X lives(X)) --> [lives]
proc {Sentence P S0#S} X P1 S1 in {NounPhrase X P1 P S0#S1} {VerbPhrase X P1 S1#S} end proc {NounPhrase X P1 P S0#S} choice P2 P3 S1 S2 in {Determiner X P2 P1 P S0#S1} {Noun X P3 S1#S2} {RelClause X P3 P2 S2#S} [] {Name X S0#S} P1 = P end end proc {VerbPhrase X P S0#S} choice Y P1 S1 in {TransVerb X Y P1 S0#S1} {NounPhrase Y P1 P S1#S} [] {IntransVerb X P S0#S} end end proc {TransVerb X Y Z S0#S} S0 = loves|S Z = loves(X Y) End proc {IntransVerb X Y S0#S} S0 = lives|S Y = lives(X) End proc {Name X S0#S} S0 = X|S
90
choice X = john [] X = jan end end proc {Noun X Y S0#S} choice S0 = man|S Y = man(X) [] S0 = woman|S Y = woman(X) end end proc {Determiner X P1 P2 P S0#S} choice S0 = every|S P = all(X imp(P1 P2)) [] S0 = a|S P = exists(X and(P1 P2)) end end proc {RelClause X P1 P S0#S} P2 in choice S1 in S0 = that|S1 P = and(P1 P2) {VerbPhrase X P2 S1#S} [] S0 = S P = P1 end end declare proc {Main P} {Sentence P [every man that lives loves a woman]#nil} end
Instruo dis:
declare Edge proc {Connected X Y} dis {Edge X Y} [] Z in {Edge X Z} {Connected Z Y} end end proc {Edge X Y} dis X = 1 Y = [] X = 2 Y = [] X = 2 Y = [] X = 3 Y = [] X = 2 Y = [] X = 5 Y = [] X = 4 Y = [] X = 6 Y =
2 1 3 4 5 6 6 7
91
[] X = 6 Y = 8 [] X = 1 Y = 5 [] X = 5 Y = 1 end end {ExploreOne proc {$ L} X Y in X#Y = L {Connected X Y} end } {Browse {SearchAll proc {$ L} X Y in X#Y = L {Connected X Y} end } }
Negao:
proc {NotP P} {SearchOne proc {$ L} {P} L=unit end $} = nil end proc {ConnectedEnh X Y Visited} dis {Edge X Y} [] Z in {Edge X Z} {NotP proc{$} {Member Z Visited} end} {ConnectedEnh Z Y Z|Visited} end end
92
5. Tutorial de Oz Distribudo
O Mozart-Oz possui um modelo de programao distribuda que consegue separar a funcionalidade da aplicao da sua estrutura distribuda. Possui tambm mecanismos para tolerncia a falhas, computao aberta, e algum suporte para segurana. Para as prximas verses ir ser dada uma maior ateno aos aspectos ainda pouco desenvolvidos deste sistema de programao, como por exemplo, a segurana. Neste tutorial podemos encontrar informao relativa programao distribuda em Mozart-Oz, nomeadamente, sobre as abstraces de programao distribuda em Oz, objectos estacionrios, agentes mveis, tolerncia a falhas, etc ..., sempre acompanhando os novos conceitos que so introduzidos, com exemplos prticos da sua aplicao. A distribuio nesta linguagem garantida por quatro mdulos: Connection Disponibiliza o mecanismo bsico (conhecidos por tickets) para a conexo entre duas aplicaes Remote Permite que uma aplicao possa criar um site e ligar-se a ele. Um site pode ser criado na mesma mquina ou num mquina remota. Pickle Permite guardar ou ler informao de URLs e ficheiros. Fault Possui mecanismos de tratamento e deteco de falhas. Para uma melhor compreenso dos assuntos referidos neste captulo recomenda-se a leitura do captulo 3, onde abordado o Oz distribudo de uma forma terica.
93
Existem trs tipos de nomes globais externos: Ticket uma string que referencia uma qualquer entidade da linguagem numa aplicao em execuo. Os tickets so criados no interior de uma aplicao Oz em execuo e podem ser usados para conectar aplicaes. URL uma string referencia um ficheiro numa rede. Em Mozart um ficheiro pode ser um pickle. Um pickle pode conter procedimentos, classes, functors, etc ... Hostname uma string que segue o sintaxe do DNS, que identifica o nome de uma mquina. O hostname pode ser usado para iniciar um processo noutra mquina.
Se por exemplo tivermos um stream e desejarmos que outras aplicaes o possam partilhar, basta associa-lo a um ticket. Se as outras aplicaes conhecerem o ticket podem comunicar e aceder ao stream. Existem a seguintes operaes sobre tickets:
{Connection.offer X T} Cria um ticket T para X. X pode ser uma qualquer entidade Oz. O ticket s pode ser utilizado uma vez, caso se tente usar mais de uma vez gerada uma excepo. {Connection.offerUnlimited X T} Cria um ticket T para a entidade X. O ticket pode ser usado um nmero de vezes ilimitado. {Connection.take T X} Cria uma referncia de uma entidade Oz para o ticket T. Isto quer dizer que, se a aplicao que criar a referncia estiver noutra mquina iro haver comunicaes pela rede.
O ticket fica com um valor semelhante a : x-ozticket://193.10.66.30:9002:SpGK0:U4v/y:s:f:xl Vejamos agora um exemplo de uma outra aplicao, que sendo executada noutra localizao referencia o mesmo stream:
declare Stream in {Connection.take x-ozticket://193.10.66.30:9002:SpGK0:U4v/y:s:f:xl Stream} {Browse Stream}
94
Como o ficheiro est localizado numa rea publica de html, pode ser acedido da seguinte forma:
declare Fact={Pickle.load "http://www.info.ucl.ac.be/~pvr/fact"} {Browse {Fact 10}}
Uma aplicao pode iniciar um computao numa mquina remota usando os recursos dessa mquina e continuar a interagir com a aplicao. As computaes so definidas como functors, pois o functor permite especificar computaes e recursos. O functor a especificao dum mdulo e da definio dos recursos que esse mdulo necessita de forma explicita.
R={New Remote.manager init(host:"sinuhe.sics.se")} F=functor export x:X define X={Fact 30} end M={R apply(F $)} {Browse M.x}
Em primeiro lugar criada uma referencia mquina remota. Depois constroi-se a computao propriamente dita, que consiste num functor que atribudo a F. O resultado X devolvido ao lado cliente no mdulo M. Outra forma usando o functor com uma referencia externa:
declare F M X in F=functor define {Fact 30 X} end M={R apply(F $)} {Browse X}
95
5.1.4 Servidores
Servidores so computaes que esto em permanente execuo e garantem servios a clientes. Vejamos partindo dum exemplo simples, como podem ser criados servidores com o Mozart-Oz.
% Cria um servidor
declare Str Prt Srv in {NewPort Str Prt} thread {ForAll Str proc {$ S} S="Ol mundo" end} end proc {Srv X} {Send Prt X} end
% O servidor fica disponivel atravs de URL: % (passando o nome do ficheiro que tambm acessvel por URL) {Pickle.save {Connection.offerUnlimited Srv} "/usr/staff/pvr/public_html/hw"}
Ir mostrar Ol mundo na janela do browser. O cliente conectando-se recebe uma referencia do servidor. Isto faz com que os espaos computacionais do servidor e do cliente sejam fundidos num s, o que faz com que o cliente e o servidor possam comunicar como se estivessem no mesmo processo. No exemplo anterior utilizou-se um port para recolher as mensagens dos clientes. Vejamos agora o mesmo exemplo utilizando objectos estacionrios. O servidor seria :
declare class HelloWorld meth hw(X) X="Hello world" end end Srv={NewStat HelloWorld hw(_)} % Requer um mtodo inicial
O cliente poderia chamar o servidor atravs de {Srv hw(X)}. As entidades estacionrias so muito importantes. O Oz possui duas formas de criar entidades estacionrias. A primeira :
96
Quando executado num site, o NewStat, recebe uma classe e um mtodo inicial e cria um objecto que estacionrio nesse site.
Um servidor de computaes pode ser escrito da seguinte forma, usando objecto estacionrios:
declare class ComputeServer meth init skip end meth run(P) {P} end end C={NewStat ComputeServer init}
O servidor pode ser disponibilizado atravs de uma URL como nos exemplos anteriores. Vejamos agora como um cliente pode usar o servidor de computaes:
declare fun {Fibo N} if N<2 then 1 else {Fibo N-1}+{Fibo N-2} end end % Executa a primeira computao remotamente local F in {C run(proc {$} F={Fibo 30} end)} {Browse F} end % Executa a segunda computao localmente local F in F={Fibo 30} {Browse F} end
Para executar uma computao remota basta usar {C run(P)}. Sendo o Oz completamente transparente o procedimento P pode ter qualquer instruo de Oz, mas se usar recursos deve ser executado remotamente atravs de funtors como j foi visto anteriormente.
97
declare R={New Remote.manager init(host:"rainbow.info.ucl.ac.be")} declare F C F=functor export cs:CS define class ComputeServer meth init skip end meth run(P) {P} end end CS={NewStat ComputeServer init} end C={R apply(F $)}.cs % Arranca o servidor
Retorna um servidor Srv e um procedimento estacionrio Upg que serve para actualizar o servidor. O servidor actualizvel porque todas as chamadas ao objecto so feitas indirectamente atravs de uma clula C. Para criar o servidor basta fazer:
declare Srv Upg in Srv={NewUpgradableStat ComputeServer init Upg}
Vejamos agora do lado cliente, como se pode actualizar o servidor sem o parar. No exemplo cria-se um novo objecto partindo de uma classe nova.
98
declare class CComputeServer from ComputeServer meth run(P Prio<=medium) thread {Thread.setThisPriority Prio} ComputeServer,run(P) end end end Srv2={Upg CComputeServer#init}
O mtodo run sobrecarregado por um novo mtodo que recebe dois parmetros : P que a computao a executar remotamente e Prio que a prioridade da thread que executa a computao P.
99
Para que o agente se possa deslocar a um determinado site, tem de haver nesse site algo que o possa receber. Esse algo so os servidores de agentes. Estes servidores aceitam functors (que representam agentes ou partes de agentes) e aplicam-nos ao site. Para instalar um servidor de agentes num site usamos o functor AgentServer. Quando o AgentServer instalado num site, cria o mdulo AS nesse site com as seguintes operaes: O servidor de agentes acedido por AS.server. Um calculo iniciado assincronamente chamando {AS.server F} onde F o functor onde est especificado o calculo e os recursos que usa. A operao {AS.publishserver FN} cria um ficheiro FN com o ticket do servidor de agentes. A operao {AS.getserver UFN ?AS} quando lhe passada uma URL ou o nome de um ficheiro UFN retorna uma referncia ao respectivo servidor de agentes. Se assumirmos que a seguinte URL conhecida:
http://www.info.ucl.ac.be/~pvr/agents.ozf
e que referencia o funtor AgentServer. O cdigo seguinte cria um servidor de agentes local e torna-o acessvel atravs da URL:
http://www.info.ucl.ac.be/~pvr/as1
Vejamos:
declare GetServer in local % le o AgentServer: AgentServer={Pickle.load http://www.info.ucl.ac.be/~pvr/agents.ozf} % Instala o AgentServer localmente: (cria um servidor de agentes) [AS1]={Module.apply [AgentServer]} % Publica o servidor de agentes {AS1.publishserver /usr/staff/pvr/public_html/as1} in GetServer=AS1.getserver End
Criemos agora um segundo agente. Este ser remoto e acessvel atravs da URL
http://www.info.ucl.ac.be/~pvr/as2 local RF=functor import Pickle Module export done:D define AgentServer={Pickle.load http://www.info.ucl.ac.be/~pvr/agents.ozf} [AS2]={Module.apply [AgentServer]} {AS2.publishserver /usr/staff/pvr/public_html/as2} end RM={New Remote.manager init} M={RM apply(RF $)} in skip end
100
Agora que j esto instalados os servidores podemos comear a programar o agente. O agente ir interrogar o sistema operativo e ir retornar as horas.
declare D1 in {Server2 functor import OS define D1={OS.time} end} {Browse D1}
Primeiro cria a varivel D1 e depois executa um agente num site remoto. O agente apenas necessita de um recurso (OS), que consiste num mdulo que disponibiliza acesso a funes do sistema operativo. Como o agente criado assincronamente, quando o Browse for executado, a varivel D1 pode ainda no estar instanciada. Isto no necessariamente um problema pois no Oz as operaes suspendem enquanto as variveis que necessitam no estiverem instanciadas. Para garantir que a varivel D1 mesmo instanciada pode usar-se {Wait D1}. Modifiquemos agora o primeiro exemplo de forma a obter um agente isolado, isto , o agente um functor que pode ser compilado e executado isoladamente ou por outra aplicao. Assumimos que o functor AgentServer est numa localizao standard.
functor import System AgentServer define GetServer=AgentServer.getserver Server2={GetServer "http://www.info.ucl.ac.be/~pvr/as2"} D1 {Server2 functor import OS define D1={OS.time} end} {System.show D1} end
A nica diferena do exemplo anterior que neste exemplo usa o GetServer para aceder ao servidor de agentes. Se o functor AgentServer no estiver numa localizao standard, o agente isolado tm que explicitamente referenciar a sua localizao.
101
functor import System Pickle Module define AgentServer={Pickle.load "http://www.info.ucl.ac.be/~pvr/agents.ozf"} [AS]={Module.apply [AgentServer]} GetServer=AS.getserver Server2={GetServer "http://www.info.ucl.ac.be/~pvr/as2"} D1 {Server2 functor import OS define D1={OS.time} end} {System.show D1} end
102
Existem duas formas de usar o AgentServer. Ou se compila com o compilador e se copia o ficheiro .ozf para uma rea publica (public_html), ou se quisermos usar o AgentServer interactivamente no OPI, temos de alterar o cdigo da seguinte maneira:
declare AgentServer= functor ... (corpo do functor) end {Pickle.save AgentServer "/usr/staff/pvr/public_html/agents.ozf"}
A vantagem de criar estas abstraces que possibilita-nos ter um programa quase igual ao programa sem ser tolerante a falhas. Vejamos o servidor com tolerncia a falhas:
103
declare Str Prt Srv in {NewPort Str Prt} thread {ForAll Str proc {$ S} try S="Hello world" catch system(dp(...) ...) then skip end end} end proc {Srv X} {SafeSend Prt X} end
{Pickle.save {Connection.offerUnlimited Srv} "/usr/staff/pvr/public_html/hw"}
A instanciao de S est na expresso try ... catch para que possa tolerar falhas dos clientes. Vejamos um cliente:
declare Srv try X in try Srv={Connection.take {Pickle.load "http://www.info.ucl.ac.be/~pvr/hw"}} catch _ then raise serverError end end {Srv X} {SafeWait X infinity} {Browse X} catch serverError then {Browse Server down} end
O cliente efectua duas operaes distribudas, o send, que substitudo pelo safeSend dentro de Srv, e o wait que substitudo pelo SafeWait. Se houver problemas no envio ou na recepo de uma mensagem gerada uma excepo serverError. Tambm so geradas excepes se existirem falhas na altura do estabelecimento de conexo, isto , na execuo das operaes Connection.take e Pickle.load. Vejamos agora a definio das operaes SafeSend e SafeWait. As funes FOneOf e FSomeOf sero definidas depois.
declare proc {SafeSend Prt X} try {Send Prt X} catch system(dp(conditions:FS ...) ...) then if {FOneOf permFail FS} then raise serverError end elseif {FOneOf tempFail FS} then {Delay 100} {SafeSend Prt X} else skip end end end
104
Gera uma excepo serverError quando existe uma falha permanente no servidor e quando existe uma falha temporria volta a tentar de 100 em 100 ms.
declare local proc {InnerSafeWait X Time} try cond {Wait X} then skip [] {Wait Time} then raise serverError end end catch system(dp(conditions:FS ...) ...) then if {FSomeOf [permFail remoteProblem(permSome)] FS} then raise serverError end if {FSomeOf [tempFail remoteProblem(tempSome)] FS} then {Delay 100} {InnerSafeWait X Time} else skip end end end in proc {SafeWait X TimeOut} Time in if TimeOut\=infinity then thread {Delay TimeOut} Time=done end end {Fault.enable X thread(this) [permFail remoteProblem(permSome) tempFail remoteProblem(tempSome)] _} {InnerSafeWait X Time} end end
Gera uma excepo serverError quando h uma falha permanente no servidor e tenta de 100 em 100 ms quando a falha temporria. A varivel X existe apenas no cliente e no servidor. Quando sucede remoteProblem(permFail:_ ...) significa que o servidor avariou. Para impedir que o cliente fique a funcionar indefinidamente introduz-se um timeout. As funes FOneOf e FsomeOf foram criadas para simplificar a verificao dos estados das falhas. A funo {FOneOf permFail AFS} true se o estado da falha permFail no conjunto de falhas AFS.
declare fun {FOneOf F AFS} case AFS of nil then false [] AF2|AFS2 then case F#AF2 of permFail#permFail(...) then true [] tempFail#tempFail(...) then true [] remoteProblem(I)#remoteProblem(I ...) then true else {FOneOf F AFS2} end end end
105
A funo {FSomeOf [permFail remoteProblem(permSome)] AFS} retorna true se permFail ou remoteProblem(permSome) ou ambos ocorrem no conjunto AFS.
declare fun {FSomeOf FS AFS} case FS of nil then false [] F2|FS2 then {FOneOf F2 AFS} orelse {FSomeOf FS2 AFS} end end
O functor definido a seguir cria uma instancia da classe usando o NewSafeStat, Note-se que o objecto ainda no criado.
declare F=functor import Fault export statObj:StatObj define {Fault.defaultEnable nil _} StatObj={NewSafeStat Counter init} End
O mdulo Fault importado porque queremos garantir que ir ser usado o Fault do site onde o functor instalado.
106
De seguida iremos criar um site remoto e uma instancia da classe Counter chamada StatObj. A classe Remote.manager d-nos a possibilidade de criar de vrias formas um site remoto. Neste exemplo usamos a opo fork:sh, que cria um processo novo na mesma mquina. O processo acessvel atravs do gestor de mdulo MM, que permite instalar functors no site remoto.
declare MM={New Remote.manager init(fork:sh)} StatObj={MM apply(F $)}.statObj
Finalmente podemos chamar o objecto. A chamada feita dentro de try catch para demonstrar a tolerncia a falhas. Se matarmos o processo remoto, veremos que continua a funcionar.
try {StatObj inc} {StatObj inc} {Show {StatObj get($)}} catch X then {Show X} end
107
remoteProblem(permSome)] proc {$} R=RL end proc {$} skip end} end end} end end proc {NewSafeStat Class Init Object} Object={MakeStat {New Class Init}} end
Vejamos agora a definio de Guarda. O guarda permite-nos substituir uma instruo S1 por outra S2 caso exista uma falha. O procedimento {Guard E FS S1 S2} primeiro desliga todas as excepes em E. Depois executa S1 com um watcher local W. Se o watcher for chamado durante a execuo de S1, ento S1 interrompido e gerada uma excepo N. Consequentemente S2 executado.
declare proc {Guard E FS S1 S2} N={NewName} T={Thread.this} proc {W E FS} {Thread.injectException T N} end in {Fault.enable E thread(T) nil _} try {LocalWatcher E FS W S1} catch X then if X==N then {S2} else raise X end end end end
Um watcher local um watcher que instalado apenas durante a execuo de uma instruo. Quando a instruo termina ou gerada uma excepo o watcher removido. O procedimento {LocalWatcher E FS W S} vigia a entidade E para os estados de falhas FS com o watcher W durante a execuo de S.
declare proc {LocalWatcher E FS W S} {Fault.installWatcher E FS W _} try {S} finally {Fault.deInstallWatcher E W _} end end
108
proc {NewSafeStat Class Init ?Object} Object={MakeStat {New Class Init}} end
Primeiro o cliente envia uma mensagem ao servidor com uma varivel de sincronizao. Esta varivel usada para sinalizar que o servidor terminou a chamada ao objecto. Se foram geradas excepes, estas so passadas ao cliente. Se existir uma falha permanente no envio, gerada a excepo remoteObjectError, caso exista uma falha temporria o envio e retentado de 100 em 100 ms.
% O cliente chama o servidor proc {StatP M} R in try {Send P M#R} catch system(dp(conditions:FS ...) ...) then if {FOneOf permFail FS} then raise remoteObjectError end elseif {FOneOf tempFail FS} then {Delay 100} {StatP M} else skip end end {EndLoop R} end
O cliente espera que o servidor instancie uma varivel de sincronizao. No caso de existir uma falha permanente gerada uma excepo, caso exista uma falha temporria espera 100 ms e tenta de novo.
109
% Sincronizao do cliente com o servidor proc {EndLoop R} {Fault.enable R thread(this) [permFail remoteProblem(permSome) tempFail remoteProblem(tempSome)] _} try if R==N then skip else raise R end end catch system(dp(conditions:FS ...) ...) then if {FSomeOf [permFail remoteProblem(permSome)] FS} then raise remoteObjectError end elseif {FSomeOf [tempFail remoteProblem(tempSome)] FS} then {Delay 100} {EndLoop R} else skip end end end
110
6 Programao Grfica
Em Mozart a programao do interfaces grficas baseada em Widgets que consistem em objectos que representam entidades graficas, como por exemplo janelas, menus, botes, etc... As janelas so descritas composicionalmente atravs de hierarquias de objectos e esto sujeitas modificaes dinmicas e interactivas. Este tipo de programao consiste num interface orientado a objectos para o Tk. Todas as caractersticas do Oz so aplicveis a este tipo de programao, tais como concorrncia e entidades first-class. Do Tk o interface herda um conjunto de abstraces bastante poderosas. O objectivo deste capitulo apenas de introduzir uma ideia geral de como pode ser construdo um interface grfico em Mozart-Oz.
Podem enviar-se mensagens para um widget para poder alterar uma das suas propriedades, por exemplo para mudar a cor do fundo do TopLevel faramos:
{W tk(configure background:purple)}
Por exemplo a mensagem tkClose serve para fechar o widget, removendoo consequentemente do ecr.
6.1.1 Frames
Os frames tm caractersticas idnticas ao toplevel, a diferena que os frames so contentores dentro de outros widgets. As opes relief e border permitem dar um aspecto tridimensional ao frame. A opo relief pode ter os seguintes valores: groove, ridge, flat, sunken, e raised.
Fs={Map [groove ridge flat sunken raised] fun {$ R} {New Tk.frame tkInit(parent:W width:2#c height:1#c relief:R borderwidth:4)} end} {{Nth Fs 3} tk(configure background:black)} {Tk.send pack(b(Fs) side:left padx:4 pady:4)}
111
Todos os widgets necessitam uma referencia a um widget pai com a excepo do toplevel.
6.1.2 Labels
Um label serve para escrever texto ou uma imagem (bitmap) numa janela. Vejamos um exemplo em que criado um label com uma imagem e outro com texto.
L1={New Tk.label tkInit(parent:W bitmap:info)} L2={New Tk.label tkInit(parent:W text:Labels: bitmaps and text)} {Tk.send pack(L1 L2 side:left padx:2#m pady:2#m)}
As fonts podem ser especificadas de uma forma dependente da plataforma, por exemplo se a plataforma for unix as fonts podem ser especificadas por um dos nomes que o comando xlsfonts devolve. No exemplo seguinte podemos ver um outro mtodo de especificar fonts independentemente da plataforma.
{ForAll [times helvetica courier] proc {$ Family} {ForAll [normal bold] proc {$ Weight} F={New Tk.font tkInit(family: Family weight: Weight size: 12)} L={New Tk.label tkInit(parent: W text: A #Weight# #Family# font. font: F)} in {Tk.send pack(L)} end} end
112
6.1.3 Imagens
A diferena entre as imagens e os bitmaps que as imagens podem ter mais de duas cores. Podemos usar os labels para mostrar imagens numa janela.
D ={Property.get oz.home}#/doc/wp/ I ={New Tk.image tkInit(type:photo format:ppm file:D#truck-left.ppm)} L1={New Tk.label tkInit(parent:W image:I)} L2={New Tk.label tkInit(parent:W image:I)} L3={New Tk.label tkInit(parent:W image:I)} {Tk.send pack(L1 L2 L3 padx:1#m pady:1#m side:left)}
As imagens podem ser de dois tipos : photo pode mostrar imagens com dois formatos: gif e ppm. bitmap o ficheiro referenciado tem que estar no formato bitmap. As imagens podem em vez de serem lidas de ficheiros, podem ser lidas a partir de uma URL da seguinte maneira:
{New Tk.image tkInit(type:photo format:gif url:http://foo.com/bar.gif}
6.1.4 Mensagens
As mensagens servem para mostrar texto em vrias linhas. O proximo exemplo mostra deferentes combinaes de justificaes e do aspecto condicionado pela opo aspect.
S =Text extending over several lines. Ms={Map [left#200 center#100 right#50] fun {$ J#A} {New Tk.message tkInit(parent:W text:S justify:J aspect:A)} end} {Tk.send pack(b(Ms) side:left padx:2#m pady:2#m)}
6.2.1 O Packer
O Packer suporta uma organizao de widgets em linhas e colunas. Vejamos um exemplo de aplicao do packer:
113
fun {NewLabels} W={New Tk.toplevel tkInit(background:white)} in {Map [label Second label widget 3rd label] fun {$ A} {New Tk.label tkInit(parent:W text:A)} end} end
Para os labels aparecerem no toplevel o packer pode ser invocado da seguinte maneira:
[L1 L2 L3] = {NewLabels} {Tk.send pack(L1 L2 L3)}
O packer tambm pode ser chamado usando um batch tickle. Um batch tickle um tuplo com um identificador b e argumento uma lista de tickles. Os tickles so mensagens enviadas ao motor grfico.
{Tk.send pack(b({NewLabels}))}
Existe uma opo (side) no packer que permite escolher a orientao dos widgets. O valor por omisso top. No exemplo seguinte os labels em vez de serem desenhados de cima para baixo, so desenhados da esquerda para a direita.
{Tk.send pack(b({NewLabels}) side:left)}
As reas ocupadas com os widgets podem ser expandidas de duas formas: interna ou externa. Espao adicional externo pode ser especificado com as opes padx e pady, e corresponde ao espao disponibilizado pela janela pai em redor dos widgets. Os valores usado nestas opes devem ser distncias de ecr. Distncias de ecr so distancias em pixeis, a no ser que antes tenham um c, m, i ou um p, que significam que as distancias so respectivamente em centmetros, milmetros, polegadas e pontos de impresso. As distancias de ecr podem ser especificadas com strings virtuais. Para especificar espao adicional interno, ou seja, o espao que cada cada um expande nas suas 4 bordas, usa-se o ipadx e o ipady.
{Tk.send pack(b({NewLabels}) padx:1#m pady:1#m)} {Tk.send pack(b({NewLabels}) ipadx:2#m ipady:2#m)}
A opo anchor em que posio dentro da parcela do packer o widget ir ser colocado. As posies podem ser center, n, s, w, e, nw, ne, sw, and se. Por omisso o widget colocado na posio central. O espao expandido pode ser preenchido totalidade do espao da parcela para isso usa-se a opo fill. Os valores possiveis so x,y e both.
{Tk.send pack(b({NewLabels}) anchor:w padx:1#m pady:1#m)} {Tk.send pack(b({NewLabels}) fill:x)}
114
6.2.2 Grids
As grids organizam os widgets na forma de grelhas. Para cada widget poder ser posicionado na grelha necessrio passar-lhe o nmero de linha e colunas desejadas. Todas as posio na mesma coluna tm o mesmo tamanho e na mesma linha tm a mesma altura. As grids tambm suportam as opo que vimos anteriormente para o packer.
proc {GL W R C S} L={New Tk.label tkInit(parent:W text:S)} in {Tk.send grid(L row:R column:C padx:4 pady:4)} end {GL W 1 1 nw} {GL W 1 2 north} {GL W 1 3 ne} {GL W 2 1 west} {GL W 2 3 east} {GL W 3 1 sw} {GL W 3 2 south} {GL W 3 3 sw}
A opo columnspan e rowspan permite que o widget ocupe mais de uma coluna ou mais de uma linha. Vejamos um exemplo:
{Tk.send grid({New Tk.label tkInit(parent:W text:Upper left)} row:1 rowspan:2 column:1 columnspan:2 padx:4 pady:4)} {GL W 1 3 ne} {GL W 2 3 east} {GL W 3 1 sw} {GL W 3 2 south} {GL W 3 3 sw}
A opo sticky especifica simultaneamente o widget ocupa todo o espao da parcela e a sua posiao dentro desta.
{Tk.send grid({New Tk.label tkInit(parent:W text:Upper left)} row:1 rowspan:2 column:1 columnspan:2 sticky: nse padx:4 pady:4)}
115
6.3.1Botes e Aces
Os botes so bastante similares aos labels, a grande diferena que os botes desencadeiam aces: quando se carrega no boto do rato por cima do boto desencadeada uma aco que consiste ou num procedimento ou num par objecto e mensagem. As aces podem ser alteradas ou apagadas com o mtodo tkAction. Vejamos um exemplo em que a aco do boto B1 eliminada, e a aco do boto B2 alterada.
{B1 tkAction} {B2 tkAction(action: B1 # tkClose)}
116
As aces nestes tipos de botes podem ser usadas da mesma forma que nos botes convencionais. Como j foi visto anteriormente a forma de aceder ao valor das variveis de tickle atravs dos mtodos tkReturnInt e tkReturnAtom. Vejamos um exemplo:
fun {GetWeight} if {V1 tkReturnInt($)}==1 then bold else normal end end F={New Tk.font tkInit(size:24 family: {V2 tkReturn($)} weight: {GetWeight})} L={New Tk.label tkInit(parent:W text:A test text. font:F)} {C tkAction(action: proc {$} {F tk(configure weight:{GetWeight})} {L tk(configure font:F)} end)} {List.forAllInd [Times Helvetica Courier] proc {$ I Family} {{Nth Rs I} tkAction(action: proc {$} {F tk(configure family:Family)} {L tk(configure font:F)} end)} end}
As opes dos widgets tambm podem ser interrogadas. Para isso usa-se o seguinte:
{T tkReturnListAtom(configure bg:unit $)}
Neste exemplo estamos a interrogar a opo bg do widget T. Vejamos que fazer para interrogar os parmetros de um widget. O exemplo seguinte interroga a posio e a geometria de um widget T.
{Browse {Map [rootx width rooty height] fun {$ A} {Tk.returnInt winfo(A T)} end}}
6.3.3 Menus
As entradas de menus no so widgets. No so geridos pelo gestor de geometria. Quando uma entrada menu criado imediatamente visualizado num menu pai. O prximo programa cria dois widgets M1 e M2. A primeira entrada de menu est configurada para mostrar M2 em cascata. A opo tearoff:false impede que o menu seja cria numa janela prpria.
Cs =[Wheat Firebrick Navy Darkorange] M1 ={New Tk.menu tkInit(parent:W tearoff:false)}
117
M2 ={New Tk.menu tkInit(parent:M1 tearoff:false)} E1 ={New Tk.menuentry.cascade tkInit(parent:M1 label:Background Color menu:M2)} E2 ={New Tk.menuentry.separator tkInit(parent:M1)} E3 ={New Tk.menuentry.command tkInit(parent:M1 label:Quit action: W#tkClose)} V ={New Tk.variable tkInit(Cs.1)} CEs={Map Cs fun {$ C} {New Tk.menuentry.radiobutton tkInit(parent:M2 label:C var:V val:C action: W#tk(configure bg:C))} end}
Normalmente os menus no so visveis. Para que o menu seja por exemplo visvel no canto superior esquerdo faz-se:
{M1 tk(post 0 0)}
No mdulo Tktools existem abstraces para criar de forma bastante simples barras de menus. Para criar menus popup usa-se o comando tk_popup. Recebe como parmetros o widget do menu e as coordenadas onde suposto aparecer. De seguida iremos ver como se associam eventos a widgets, por exemplo, para fazer aparecer o menu quando se pressiona o boto direito do rato.
6.3.4 Eventos
Para associar uma aco a um widget usa-se o comando tkbind. A aco invocada quando um determinado evento sucede. Vejamos o que teramos de fazer para que, no exemplo anterior, o menu seja visualizado quando se pressionar o boto do rato sobre o toplevel.
{W tkBind(event: <Button-1> args: [int(x) int(y)] action: proc {$ X Y} TX={Tk.returnInt winfo(rootx W)} TY={Tk.returnInt winfo(rooty W)} in {Tk.send tk_popup(M1 X+TX Y+TY)} end)}
A seguir opo event especificado o tipo de evento chamado de padro de evento, na opo args especificada uma lista com os paramentos do evento. Os padres tm a seguinte forma:
< Um caracter > Significa que a tecla correspondente a esse caracter foi primida <#Modifier#-#Modifier#-#Type#-#Detail#> ou <#Type#> ou apenas <#Detail#>
118
Exemplos de modifiers:
Control Shift Lock Meta Alt Button1, B1 Button2, B2 Button3, B3 Button4, B4 Button5, B5 Double Triple
Se no for especificada nenhuma aco na respectiva opo, a aco que anteriormente estava associada a esse evento ser eliminada. Para adicionar aces a um evento usa-se a opo append, que significa que a nova aco especificada no ir ser sobreposta anterior. Os Listeners garantem que as mensagem das aces so processadas pela ordem que so invocadas. Podem ser criados derivando uma classe da classe Tk.listener.
L ={New class $ from Tk.listener meth b1 {Browse b1} end meth b2 {Browse b2} end end tkInit} B1={New Tk.button tkInit(parent:W text:One action: L#b1)} B2={New Tk.button tkInit(parent:W text:Two action: L#b2)} {Tk.send pack(B1 B2 side:left)}
Neste exemplo garantimos que os mtodos b1 e b2 so executados com a mesma ordem que os botes correspondentes so primidos.
6.3.5 Entries
Uma entry permite-nos inserir uma linha de texto. Vejamos um exemplo:
L={New Tk.label tkInit(parent:W text:File name:)} E={New Tk.entry tkInit(parent:W width:20)} {Tk.batch [pack(L E side:left pady:1#m padx:1#m) focus(E)]}
O comando focus serve para atribuir o foco entry para que o texto digitado aparea nesse widget. Para ler o contedo da entry usa-se o comando get da seguinte forma:
{Browse {E tkReturnAtom(get $)}}
119
6.3.6 Scales
O scale widget, permite seleccionar um determinado valor movendo um slider que desliza sobre uma barra. Cada vez que o slider movido, um aco associada invocada com um nico argumento, que o valor para o qual o slider aponta. Vejamos um exemplo que cria trs barras com as corres RGB.
L ={New class $ from Tk.listener attr red:0 green:0 blue:0 meth bg(C I) C <- I {F tk(configure bg:c(@red @green @blue))} end end tkInit} F ={New Tk.frame tkInit(parent:W height:2#c)} Ss={Map [red green blue] fun {$ C} {New Tk.scale tkInit(parent:W orient:horizontal length:8#c label: C from:0 to:255 action: L # bg(C) args: [int])} end} {Tk.send pack(b(Ss) F fill:x)}
6.3.7 Listboxes
Uma listbox mostra uma lista de strings e permite o utilizador seleccionar uma delas. Para associar a uma listbox um elevador, usa-se o procedimento Tk.addYScrollbar. Este procedimento associa os eventos do elevador s strings visveis na listbox. Vejamos um exemplo:
L={New Tk.listbox tkInit(parent:W height:6)} {L tkBind(event: <1> action: proc {$} I={L tkReturn(curselection $)} C={L tkReturn(get(I) $)} in {L tk(configure bg:C)} end)} S={New Tk.scrollbar tkInit(parent:W)} {ForAll NomesDeCores proc {$ C} {L tk(insert end C)} end} {Tk.addYScrollbar L S} {Tk.send pack(L S fill:y side:left)}
120
Existem vrios comandos para manipular a janela toplevel. Por exemplo o comando seguinte:
{Tk.send wm(iconify T)}
Cria uma janela toplevel com o titulo Meu Titulo. Para se poder criar um toplevel que no aparea imediatamente quando criado no ecr, e s apareca depois de todos os widgets que ir conter serem criados, faz-se da seguinte maneira:
W={New Tk.toplevel tkInit(withdraw:true)}
6.4 O Canvas
Os widgets Canvas servem para manipular entidades grficas, tais como linhas, arcos, pontos, etc...
121
Para ser mais fcil entender como funciona o canvas iremos partir de um exemplo prtico. Antes de um elemento ser criado pelo mtodo bars, o canvas configurado de forma a que o grfico de barras caiba na zona definida com elevadores. O mtodo drawBars cria para cada elemento da lista Ys um rectngulo e um texto correspondendo a um determinado valor. O valor de O usado como opo na criao do rectngulo. Este valor depende de Tk.isColor que true se o ecr for colorido e false se no for colorido. Isto serve para determinar as corres dos rectngulos. Se o ecr for a preto e branco os rectngulos so preenchidos com listas. Cada canvas identificado por um valor inteiro que pode ser obtido pelo mtodo tkReturnInt. Para ser mais fcil manipular elementos ou grupos de elementos do canvas existe o conceito de etiquetas (Tags) que podem ser manipuladas como objectos. Uma etiqueta pode ser criada atravs da classe Tk.canvasTag. Por exemplo:
R={New Tk.canvasTag tkInit(parent:C)} {C tk(create rectangle 10 10 40 40 fill:red tags:R)}
Para manipular simultaneamente todos os elementos de uma etiqueta podemos fazer por exemplo:
{R tk(move 40 0)}
Para configurar um elemento do canvas pode usar-se o comando itemconfigure que semelhante ou configure para os widgets. As cores da oval e do rectngulo do exemplo anterior podem ser modificadas usando:
{R tk(itemconfigure fill:wheat)} % preto e branco com listas {O tk(itemconfigure fill:blue)} % cor azul
Apaga todas as ovais associadas etiqueta O. Vejamos agora o exemplo do programa do grfico de barras:
122
local O=if Tk.isColor then o(fill:wheat) else o(stipple:gray50 fill:black) end D=10 D2=2*D B=10 in class BarCanvas from Tk.canvas meth DrawBars(Ys H X) case Ys of nil then skip [] Y|Yr then {self tk(create rectangle X H X+D H-Y*D2 O)} {self tk(create text X H+D text:Y anchor:w)} {self DrawBars(Yr H X+D2)} end end meth configure(SX SY) {self tk(configure scrollregion:q(B ~B SX+B SY+B))} end meth bars(Ys) WY=D2*({Length Ys}+1) HY=D2*({FoldL Ys Max 0}+1) in {self configure(WY HY)} {self DrawBars(Ys HY D)} end end end
6.4.2 Eventos
De modo similar aos widgets, tambm se podem utilizar eventos associados etiquetas. Um evento associado a uma etiqueta significa que fica associado a todos o elementos que ela referencia. Vejamos a atribuio de eventos a uma oval:
Colors={New class $ from BaseObject attr cs:(Cs=red|green|blue|yellow|orange|Cs in Cs) meth get(?C) Cr in C|Cr = (cs <- Cr) end end noop} {O tkBind(event: <3> action: proc {$} {O tk(itemconfigure fill:{Colors get($)})} end)}
123
Para no serem tomados em conta os espaos entre as palavras, mas preservando os limites das palavras, faz-se o seguinte:
{T tk(configure wrap:word)}
Pores do texto podem ser associadas a tickles p(L C), em que L a linha e C a coluna. As pores texto pode ser acedidas usando o seguinte:
{T tkReturnAtom(get p(1 4) p(1 9) $)}
As pores tambm podem ser usadas para determinar onde iremos inserir texto.
{T tk(insert p(1 4) "texto")}
Da mesma forma podemos eliminar texto. No exemplo o texto ente as posies p(1 4) e p(1 14) eliminado.
{T tk(delete p(1 4) p(1 14))}
124
Todos os caracteres associados a esta etiqueta iro ser castanhos. Pode-se adicionar texto a uma etiqueta da seguinte maneira:
{B tk(add p(1 10) p(1 15))}
O comando insert tambm pode ser utilizado para inserir ou adicionar texto directamente a uma etiqueta.
{T tk(insert end "\nTexto1 ")} {T tk(insert end "Texto2" B)} {T tk(insert end " Texto3.")}
As marcas so idnticas s etiquetas, s que em vez de referenciarem caracteres, referenciam posies no texto. A classe que suporta as marcas Tk.textMark.
6.6.1 Dialogs
Dialogs ou caixas de dialogo consistem em janelas que possuem alguma informao grfica e botes. Para criar este tipo de janelas usa-se a classe TkTools.dialog. A criao da dialog contem uma opo tiltle para o titulo. Os botes so especificados em listas de pares, onde o primeiro par o boto mais direita. Estes pares so constitudos pelo identificador do boto e a aco correspondente. A aco pode ser um procedimento ou por exemplo o tomo tkClose que envia uma mensagem para fechar a dialog. Pode tambm ser um tuplo com o identificador tkClose, que significa que antes de ser fechada a dialog executado o argumento do tuplo, que pode ser um procedimento. A opo default especifica qual o boto escolhido por omisso. Vejamos um exemplo de uma dialog para apagar um ficheiro.
D={New TkTools.dialog tkInit(title: Eliminar um Ficheiro buttons: [Ok # proc {$} try
125
{OS.unlink {E tkReturn(get $)}} {D tkClose} catch _ then skip end end Cancelar # tkClose] default: 1)} L={New Tk.label tkInit(parent:D text:Nome do Ficheiro:)} E={New Tk.entry tkInit(parent:D bg:wheat width:20)} {Tk.batch [pack(L E side:left pady:2#m) focus(E)]}
126
var:V value:0) radiobutton(label:Middle var:V value:1) radiobutton(label:Large var:V value: 2)])])] nil} F={New Tk.frame tkInit(parent:W width:10#c height:5#c bg:ivory)} {Tk.send pack(B F fill:x)}
A opo feature associa propriedades aos botes de menu e aos items de menu, de forma a que seja acessveis. Podem ser usadas por exemplo para desactivar uma opo:
{B.test.about tk(entryconfigure state:disabled)}
127
7. Concluso
Penso que este tutorial uma boa ferramenta para introduzir o sistema de programao Mozart-Oz. Obviamente, devido vastido de assuntos que so includos neste tutorial, no possvel detalh-los a todos com maior profundidade. No entanto, escolhi focar as questes que me pareceram mais fundamentais, quer para entender como se programa com esta poderosa linguagem de programao, que o Oz, quer para compreender os modelos subjacentes a essa programao. Tive algumas duvidas em incluir o capitulo dedicado programao grfica, pois no me pareceu um aspecto fundamental da introduo programao neste sistema. Decidi inclu-lo porque hoje em dia, quando se estuda uma linguagem de programao e no se foca os aspecto grficos dessa linguagem normalmente desmotivador. Para alm disso, relativamente fcil programar interfaces grficos em Mozart, porque as abstraces de programao so simples de compreender e so baseadas no Tk. O modelo de programao distribuda na minha opinio aquilo que torna este sistema de programao realmente brilhante. Isto obviamente possvel graas s extraordinrias caractersticas que a linguagem de programao Oz possui, nomeadamente o facto de tudo em Oz ser first-class, o que possibilita que aplicaes distribudas sejam praticamente iguais a aplicaes centralizadas, isto , separa-se completamente as questes da distribuio da funcionalidade dos programas. Eu penso que o Oz marcar certamente uma nova era na programao. As linguagens de programao convencionais no conseguem dar respostas a todos os problemas. Existe nos dias de hoje uma tendncia para a programao de computaes mveis e programao de agentes que possam existir em qualquer site e movimentarem-se numa rede local ou na internet. Creio que o Oz, apesar de algumas lacunas que ainda tem, nomeadamente em questes de segurana, a ferramenta mais apropriada para o desenvolvimento deste tipo de programas. Vimos tambm neste tutorial a comparao entre o desempenho do Oz e do Java, numa aplicao produtor / consumidor. Os resultados demonstram a ineficincia do Java para este tipo de problemas, e a ineficincia ainda maior quando a aplicao distribuda. O Oz vem provar que o java uma linguagem desactualizada e inadequada aos problemas que a computao distribuda prope nos dias de hoje. Foi para mim um grande prazer desenvolver este tutorial. Nunca tinha tido contacto com este sistema de programao antes. Espero que seja tambm do agrado das pessoas que o vierem a ler e a utilizar como ferramenta. Espero tambm que o Mozart tenha um excelente futuro. Parabns aos professores Seif Haridi, Peter Van Roy, Per Brand e a tantos outros que trabalharam neste excelente projecto.
128
Apndice A
Os programas dos testes de performance entre o Oz e o Java
A.1 Produtor Consumidor Centralizado em Java
import java.util.*; /** This is where the example is run. */ public class ProdCons { public static void main(String[] args) { long starttime = (new Date()).getTime(); Buffer buffer=new Buffer(); Consumer c=new Consumer(buffer); Producer p=new Producer(buffer,1000000); c.start(); p.start(); try { c.join(); } catch (InterruptedException e) {} try { p.join();import java.util.*; /** The buffer class acts as the glue between the Producer and the Consumer. Here the Producer puts his products and from here the consumer retrievs them */ public class Buffer { LinkedList list = new LinkedList(); public synchronized void put(Integer i) { list.addLast(i); notifyAll(); } public synchronized Integer get() { if (list.size() == 0) try { wait(); } catch (InterruptedException e) {} return (Integer) list.removeFirst(); } } } catch (InterruptedException e) {} long endtime = (new Date()).getTime(); System.out.println("Time (milliseconds): "+ Long.toString(endtime-starttime));
129
System.out.println("The sum is: "+c.getSum()); } } public class Producer extends Thread { Buffer buffer; int times; Producer(Buffer buffer, int times) { this.buffer = buffer; this.times = times; } public void run() { for (int i=times;i>0;i--) { Integer n = new Integer(i); buffer.put(n); } buffer.put(null); // Tells the consumer that we are done. } } public class Consumer extends Thread { Buffer buffer; long sum; Consumer(Buffer buffer) { this.buffer = buffer; sum = 0; } public void run() { Integer i; while(true) { i = buffer.get(); if (i==null) break; else sum += i.intValue(); } } public long getSum() { return sum; } }
130
import java.rmi.Remote; import java.rmi.RemoteException; public interface Buffer extends Remote { public void put(Integer i) throws RemoteException; public Integer get() throws RemoteException; public void waitForStart(Waiter w) throws RemoteException; public void start() throws RemoteException; } import import import import java.rmi.*; java.rmi.registry.*; java.rmi.server.*; java.util.*;
public class BufferImpl extends UnicastRemoteObject implements Buffer { LinkedList list = new LinkedList(); Waiter w; BufferImpl() throws RemoteException {
131
super(); } public void put(Integer i) { putSynch(i); } // Java does not allow remote methods to be synchronized, // therefore we have to synchronize locally. private synchronized void putSynch(Integer i) { list.addLast(i); notifyAll(); } public Integer get() { return getSynch(); } // Java does not allow remote methods to be synchronized, // therefore we have to synchronize locally. private synchronized Integer getSynch() { if (list.size() == 0) try { wait(); } catch (InterruptedException e) {} return (Integer) list.removeFirst(); } /////////////////////// // For timing purposes public void waitForStart (Waiter w) { this.w=w; } public void start() { try { w.startup(); } catch (RemoteException e) { System.err.println("Could not start "+w); } } ////////////////////// public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } String name = "//" + args[0] + "/Buffer"; try { // Create a "name-server" and store infomation of // this buffer there. LocateRegistry.createRegistry(1099); BufferImpl bufferImpl = new BufferImpl(); Naming.rebind(name, bufferImpl); } catch (Exception e) { System.err.println("BufferImpl exception: " + e.getMessage()); } } }
import java.rmi.*;
132
import java.util.*; public class Consumer extends Thread { Buffer buffer; long sum; Consumer(Buffer buffer) { this.buffer = buffer; sum = 0; } public void run() { Integer i; try { while(true) { i = buffer.get(); if (i==null) { break; } else sum += i.intValue(); } } catch (RemoteException e) { System.err.println("Consumer exception: " + e.getMessage()); } } public long getSum() { return sum; } // Now the consumer is a standalone application. public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "//" + args[0] + "/Buffer"; // Find the buffer from the "name-server" Buffer buffer = (Buffer) Naming.lookup(name); Consumer c = new Consumer(buffer); long starttime = (new Date()).getTime(); buffer.start(); c.start (); try { c.join(); } catch(InterruptedException e2) {} long endtime = (new Date()).getTime(); System.out.println("Time (milliseconds): "+ Long.toString(endtime-starttime)); System.out.println("The sum is: "+c.getSum()); } catch (Exception e) { System.err.println("Consumer exception: " + e.getMessage()); e.printStackTrace(); } } }
133
import java.rmi.*; public class Producer extends Thread { Buffer buffer; int times; Producer(Buffer buffer, int times) { this.buffer = buffer; this.times = times; } public void run() { try { for (int i=times;i>0;i--) { Integer n = new Integer(i); buffer.put(n); } buffer.put(null); } catch (RemoteException e) { System.err.println("Producer exception: " + e.getMessage()); } } // Now the producer is a standalone application. public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } try { String name = "//" + args[0] + "/Buffer"; // Find the buffer from the "name-server" Buffer buffer = (Buffer) Naming.lookup(name); Producer p = new Producer(buffer, 1000000); buffer.waitForStart(new ProdWaiter(p)); } catch (Exception e) { System.err.println("Producer exception: " + e.getMessage()); e.printStackTrace(); } } }
import java.rmi.*; import java.rmi.server.*; /** This is simply a construction to start the Producer at a given moment, to make it possible to time the process. */ public class ProdWaiter extends UnicastRemoteObject implements Waiter { Producer p; ProdWaiter(Producer p) throws RemoteException { this.p=p; } public void startup() { p.start(); }
134
} import java.rmi.Remote; import java.rmi.RemoteException; /** This is simply a construction to start the Producer at a given moment, to make it possible to time the process. */ public interface Waiter extends Remote { public void startup() throws RemoteException; } /* java.policy */ grant { permission java.net.SocketPermission *:1024-65535, connect,accept; permission java.net.SocketPermission *:80, connect; };
declare S Trig FileName='/home/perbrand/public_html/ticket' {Save {Connection.offer S#Trig} FileName} proc{Producer Stream Cur No} if No>0 then Stream1 in Stream=Cur|Stream1 {Producer Stream1 Cur+1 No-1} else Stream=nil end end {Wait Trig} {Producer S 1 1000000} /* Trig=unit */ functor import Connection Pickle Application System define FileName={Application.getArgs record('url'(single type:atom))}.url _#Trig ={Connection.take {Pickle.load FileName}} {System.show initiating} Trig=unit {System.show done} {Application.exit 0} end declare S T1 T2 Trig FileName='http://www.sics.se/~perbrand/ticket' S#Trig={Connection.take {Load FileName}} fun{Consumer Stream Acc} case Stream of S1|Ss then
135
{Consumer Ss Acc+S1} [] nil then Acc end end {Wait Trig} {Property.get time T1} Res={Consumer S 0} {Property.get time T2} {Show result(result:Res time:T2.user -T1.user)}
136
Apndice B
Nomes de Cores
___
[aliceblue azure black blueviolet cadetblue coral cyan darkgoldenrod darkgrey darkolivegreen darkred darkslateblue darkturquoise deepskyblue dodgerblue forestgreen gold green honeydew ivory lavenderblush lightblue lightgoldenrod lightgreen lightsalmon lightslateblue lightsteelblue linen mediumaquamarine mediumpurple mediumspringgreen midnightblue moccasin navyblue orange palegoldenrod palevioletred peru powderblue rosybrown salmon seashell slateblue snow tan turquoise wheat yellow
antiquewhite beige blanchedalmond brown chartreuse cornflowerblue darkblue darkgray darkkhaki darkorange darksalmon darkslategray darkviolet dimgray firebrick gainsboro goldenrod greenyellow hotpink khaki lawngreen lightcoral lightgoldenrodyellow lightgrey lightseagreen lightslategray lightyellow magenta mediumblue mediumseagreen mediumturquoise mintcream navajowhite oldlace orangered palegreen papayawhip pink purple royalblue sandybrown sienna slategray springgreen thistle violet white yellowgreen]
aquamarine bisque blue burlywood chocolate cornsilk darkcyan darkgreen darkmagenta darkorchid darkseagreen darkslategrey deeppink dimgrey floralwhite ghostwhite gray grey indianred lavender lemonchiffon lightcyan lightgray lightpink lightskyblue lightslategrey limegreen maroon mediumorchid mediumslateblue mediumvioletred mistyrose navy olivedrab orchid paleturquoise peachpuff plum red saddlebrown seagreen skyblue slategrey steelblue tomato violetred whitesmoke
137
Apndice C
Glossrio de alguns termos
Agentes Computaes que exibem pelo menos os seguintes comportamentos: autonomia, comportamento reactivo, comportamento pr-activo e comportamento social. Agentes Inteligentes Agentes que exibem comportamentos semelhantes inteligncia humana (raciocnio, aprendizagem). Agentes Mveis Agentes com a capacidade de se deslocarem entre localizaes e com autonomia para decidir a que localizao se deslocam. Aninhamento ou Embutimento de Instrues Consiste em embutir instrues dentro de outras instrues. Avaliao Eager A avaliao de alguns ou todos os parmetros de uma funo iniciada antes do seu valor ser requerido. Um exemplo tipico o call-byvalue em que todos os argumentos so passados depois de avaliados. Avaliao Lazy A avaliao de uma expresso apenas feita se for necessria para que a funo retorna um valor. Em situaes em que o valor de uma expresso necessrio mais do que uma vez, o resultado da primeira avaliao relembrado. Computao Aberta So computaes (aplicaes) que so desenvolvidas de forma a poderem comunicar com outras, independentemente da plataforma e da linguagem de implementao. A comunicao feita atravs de sockets ou ficheiros. Full Laziness a modificao de um programa tendo em vista a optimizao da avaliao lazy, de modo a que todas as subexpresses no corpo da funo que no dependem dos argumentos, sejam apenas avaliados uma vez. Handlers Mecanismos de deteco de falhas de distribuio que consistem em executar um procedimento quando uma instruo sobre uma determinada entidade distribuda falha. High Order As funes ou procedimentos podem receber como argumento outras funes ou procedimentos e podem tambm retornar outras funes ou procedimentos. Lambda-Calculus Um ramo da matemtica desenvolvido por Alonzo Church nos anos 30 e anos 40, relacionado com a aplicao das funes aos seus argumentos. O puro Lambda-Calculus no possui constantes, nem nmeros nem operadores. Consiste em abstraces lambda (funes), variveis e aplicao de uma funo noutras. Todas as entidades so representadas por funes. Por
138
exemplo um nmero natural pode ser representado como uma funo que aplica o seu primeiro argumento ao seu segundo N vezes (Inteiro de Church). As linguagens funcionais so extenses ao Lambda-Calculus introduzindo constantes e tipos. Linguagens Declarativas Computao directa (Linguagens de programao Funcional) e computao indirecta (Linguagens de programao em Lgica). Lgica Determinista Programao lgica em que a sequncia de execuo do algoritmo conhecida. Lgica no Determinista Programao lgica em que a sequncia de execuo do algoritmo desconhecida, isto , existem vrios caminhos alternativos partindo de um ponto de escolha. Multi-Agentes Vrios Agentes em cooperao e/ou competio. Objectos Estacionrios Objectos que permanecem numa localizao (site). Objectos Mveis Objectos que se movimentam entre sites. OPI Oz Programming Interface. o ambiente de desenvolvimento do Mazart-Oz. Consiste em vrios programas utilitrios e na integrao com o Emacs. Procedimentos Annimos uma forma de definir um bloco de instrues. Isto permite que estes blocos de instrues sejam embutidos dentro de chamadas a procedimentos. Servidores de Computao So aplicaes que aceitam pedidos de computao remota processam essas computaes e devolvem um resultado. Servem para tirar partido dos recursos da rede para melhorar o desempenho do sistema. Servidores Dinamicamente Extensvel So servidores que podem ser actualizados sem que tenham que ser desligados. Threads Unidades computacionais da programaes concorrente que consistem num conjunto de instrues executadas em concorrncia. Tickets So strings que servem para identificar uma determinada entidade distribuda. Valores First-Class Um valor first-class quando pode ser passado como parmetro ou devolvido por uma funo e pode tambm ser guardado em estruturas de dados. O conceito semelhante a high order. Watchers Mecanismos de deteco de falhas de distribuio que consistem em executar um determinado procedimento quando uma determinada entidade distribuda falha independentemente se executada ou no uma instruo sobre essa entidade.
139
Bibliografia
Site Oficial www.mozart-oz.org
Jason Cecil, Mike Reily, Jason Sutton, Mike Tolliver; A Comparative Report of Simple Procedural vs. Functional Programming Languages and Functional vs. Logic-Based Programming Languages; 24/4/2000 Constraint Logic Programming; Revista Byte; 2/1995 The Journal of Functional Programming; MIT press Gert Smolka; The Oz programming Model; DFKI; 1995 Seif Haridi, Peter Van Roy, Per Brand e Christian Schulte; Programming Languages for Distributed Applications; 1998 Seif Haridi, Peter Van Roy, Gert Smolka ; An Overview of the Design of Distributed Oz; 1997 Seif Haridi, Peter Van Roy, Per Brand e Christian Schulte, Denis Duchier, Martin Henz; Logic Programming in Oz and its relation to multiparadigm programming; 2000 Seif Haridi, Nils Fransn; Tutorial of Oz; 2/2000 Seif Haridi, Peter Van Roy, Per Brand; Distributed Programming in Mozart ATutorial Introduction; 2/2000 Christian Schulte; Window Programming in Mozart; 2/2000
140
141