Telis

Programação na linguagem Telis

Como faço dois atores se comunicarem?

Existem 3 formas de comunicação entre atores, comunicação direta, perguntar/se perguntado e dizer/se dito.

A comunicação direta é a mais simples, utilizada para se comunicar diretamente com atores do mesmo aplique, utiliza a notação de ponto que é similar a invocação de métodos nas linguagens orientadas a objetos.

Com o dizer/seDito é possível se comunicar com atores que estejam ouvindo um determinado tipo de estimulo(filtro), estes atores podem inclusive estar em outra página(alcance página) ou mesmo outro computador(alcance internet), porém não se garante que o estimulo vai ser ouvido(o ator que ouve pode estar tratando de outro estimulo no momento).

O perguntar/sePerguntado é utilizado quando o ator que pergunta(através da primitiva perguntar) precisa ser informado se o outro lado(sePerguntado) recebeu o estimulo, é a forma mais segura de comunicação pois se pode afirmar quando um dos lados recebeu o estímulo.

Para mais informações sobre perguntar/sePerguntado e dizer/seDito visite: Programação Orientada a Serviços

Como são tratados os diferentes tipos de comunicação de atores?

A comunicação direta (via ponto) é o estímulo de prioridade mais baixa, durante o seu tratamento qualquer outro tipo de estímulo o interrompe e o tratamento da comunicação direta é retomada quando o tratamento dos outros estímulos for completado (note que uma comunicação direta não interrompe outra, ao invés disso os pedidos são enfileirados para futuro tratamento).

Os estímulos perguntar/sePerguntado são os segundos mais prioritários. O tratamento destes estímulos não são interrompidos por estímulos de comunicação direta.

Os estímulos dizer/seDito são os estímulos mais prioritários que existem em Telis, interrompendo o tratamento de qualquer outro tipo de estímulo. Além disso não podem ser interrompidos, nem mesmo para tratamentos de outros estimulos dizer/seDito. Quando um estímulo dizer/seDito está sendo tratado e um novo estímulo dizer/seDito chega ele é perdido, caso seja algum outro tipo de estímulo ele é enfileirado para ser tratado após o término do tratamento do seDito.

Para mais informações sobre perguntar/sePerguntado e dizer/seDito visite: Programação Orientada a Serviços

Como uso um GIF animado com o Telis?

Telis tem suporte a GIF's como ícones de atores.

Você pode utilizar GIF's com a primitiva fixarÍcone?.

A primitiva fixarÍconeGirável? também pode ser utilizada, mas quando se gira um GIF animado ele perde a animação, ou seja é mantido apenas um dos quadros da imagem.

A primitiva esticarImagem estica a imagem, mantendo a animação, enquando a primitiva mostrar mostra apenas um quadro da imagem.

Quais estímulos a colisão entre atores emite?

O que chamamos colisão entre atores na verdade é a colisão entre os ícones visíveis dos atores. Nestas colisões é necessário que pelo menos um dos atores esteja tangível, o que é realizado pela primitiva tangível.

Cada ator tangível emitirá, ao colidir, uma tupla de 7 elementos:

[ texto texto "colidiu com" texto texto lista lista ]

E ao parar de colidir:

[ texto texto "parou de colidir com" texto texto lista lista ]

Sendo estes os significados dos campos:

Um exemplo de uma colisão seria:

atorTangível:

visível 
tangível 

outroAtor:

visível 
[ texto texto texto texto texto lista lista ] 
[ 
   -20 frente 
   mostrar 
] seDito 
 
1 descansar 
-50 frente

Invocando ambos...

outroAtor 0.2 descansar atorTangível

Seria mostrado algo similar à:

[atorTangível 95957 "colidiu com" outroAtor 95959 [0 100] [0 100]]

[atorTangível 95957 "parou de colidir com" outroAtor 95959 [0 100] [0 30]]

Observações

É importante salientar que ao executar uma trajetória (100 frente por exemplo) o ícone do ator fica invisível durante o percurso, voltando a estar visível apenas ao final deste. Lembrando que "colisão entre atores na verdade é a colisão entre os ícones visíveis dos atores", caso nesse percurso o ator tangível "atravesse" um outro ator, nenhum estímulo de colisão será emitido. Uma solução para isso seria segmentar a trajetória, aumentado assim as chances da colisão entre os ícones, usando [10 frente] 10 vezesRepetir ao invés de 100 frente, por exemplo.

Como criar escolhas Múltiplas em Telis?

Imagine um ator de nome "usaEscolha", que necessita fazer algo caso um determinado valor seja igual a 5. Mas, o ator precisa fazer outra coisa se o valor for maior do que sete; outra ainda caso o valor seja menor do que dois, etc.

Este é tipicamente um caso de "Escolha Múltipla", ou simplesmente "Escolha".

Como esta é uma situação bastante comum, muitas linguagens contem uma estrutura de controle adequada pra tratar disso. Principalmente aquelas pensadas dentro do paradigma denominado "Programação Estruturada", que se preocupa em oferecer ao programador um determinado numero de estruturas "bem-comportadas" de controle do fluxo de execução do programa.

Em Telis, uma agenda de usuário de nome "escolher" distribuida junto com o ambiente cumpre esta função.

Sua forma de uso é:


valor
[
   [ condição1 para "valor" ] [ comando à ser executado caso a condição1 seja verdadeira ]
   [ condição2 para "valor" ] [ comando à ser executado caso a condição2 seja verdadeira ]
   .
   .
   [ condiçãoN para "valor" ] [ comando à ser executado caso a condiçãoN seja verdadeira ]

] escolher

Exemplo:


5 
[ 
   [ 3 menorQue ] [ 20 frente "menor que 3" mostrar ] 
   [ 5 = ] [ 20 frente "igual a 5"  mostrar ] 
   [ 7 = ] [ 20 frente "igual a 7" mostrar ]
] escolher

O exemplo acima imprime "igual a 5" na tela, pois esta é a ação relacionada a condição que retornou verdadeiro.

Como efetuar a comunicação entre atores através da primitiva perguntar?

Além da primitiva dizer, que envia uma mensagem sem aguardar resposta ou confirmação de recebimento, Telis também possui primitivas de comunicação síncrona, que permitem o envio de uma mensagem e o bloqueio do programa no aguardo de uma resposta.

As primitivas envolvidas são perguntar, para emitir a mensagem, responder, para enviar tuplas ao ator que utilizou o perguntar e ainda sePerguntado para instalar um receptor à esse tipo de pergunta.

A primitiva perguntar

Assim como a primitiva dizer a primitiva perguntar emite a mensagem na forma de uma tupla. Além disso, ela especifica o tratamento a ser dado à resposta, assim como o que deve ser feito caso a resposta não seja recebida dentro de um prazo pré-determinado.

Vejamos um exemplo, um "cliente de baralho":

   3
   [ "servidor_de_baralho" novo 10 ]
         [ sucesso ]
         [ fracasso ]
   perguntar 

Nesse caso, o ator está enviando uma mensagem na forma de uma tupla de 3 elementos (um texto, um símbolo e um número). Caso algum outro ator esteja preparado para responder a essa mensagem, ele irá produzir uma resposta, também na forma de tupla, e enviá-la (somente) ao ator que emitiu o "perguntar". Esta resposta será colocada na pilha do ator, de forma a estar disponível no início do código de "sucesso", no exemplo acima. Após a execução do código "sucesso", o fluxo de controle passaria para o comando seguinte ao comando "perguntar". Caso nenhum ator responda à mensagem emitida dentro de um prazo de 3 segundos, será então acionada automaticamente a agenda "fracasso". Depois disso, assim como no caso de "sucesso", seria executado o comando seguinte ao comando "perguntar".

O atributo alcance do ator, fixado pela primitiva fixarAlcance, assim como na primitiva dizer é determinante na comunicação entre os atores. A pergunta de um ator que tenha esteja num determinado alcance só poderá ser respondido por um tratador para aquela pergunta que tenha sido instalado nesse mesmo alcance. Lembrando que o alcance de um tratador depende apenas do alcance do ator na hora que instalou o tratador, não importando a mudança posterior de alcance pelo ator. Os alcances disponíveis assim como no dizer são: aplique, página, máquina e rede.

Dentro do alcance selecionado, qualquer outro ator poderá "responder" à mensagem enviado pelo "perguntar". Assim, vários atores podem responder à mesma mensagem. Apenas a primeira resposta recebida pelo ator que utilizou o "perguntar" será utilizada.

A primitiva responder

A primitiva que permite enviar uma resposta é responder Esse comando possibilita enviar uma tupla diretamente ao ator que emitiu o perguntar. Para responder ao pedido do exemplo anterior, por exemplo, um ator "servidorDeBaralho" poderia utilizar:

[ @baralho ] responder

Nesse exemplo, o ator envia como resposta uma lista contendo o valor atual de uma variável local chamada "baralho". Note-se que o comando "responder" não pode ser utilizado isoladamente, em um ponto qualquer do programa. Esse comando só pode ser usado dentro do contexto de um "serviço" de resposta, ou seja: um trecho de código que especifique o procedimento de produção da resposta, e especialmente o tipo de mensagens que devem ser respondidas.

A primitiva sePerguntado

A instalação de um "serviço" para responder ao perguntar é feita através do comando sePerguntado . Tal como no comando seDito, deve ser fornecido um molde do tipo de tuplas esperadas, assim como o procedimento a ser executado caso alguma tupla "case" com esse molde. Esse procedimento é o (único) contexto no qual poderá ser utilizada a primitiva responder. Continuando com o exemplo anterior , um ator "servidorDeBaralho" poderia instalar o seguinte serviço:

   [ "servidor_de_baralho" novo número ]
      [
      último gerarBaralho [ @baralho ] responder
      ]
   sePerguntado

Esse ator poderia tratar o pedido do ator "clienteDeBaralho", pois a tupla [ "servidor_de_baralho" novo 10 ] "casa" com o molde especificado pelo servidor: [ "servidor_de_baralho" novo número ] .

No momento da recepção da tupla, ela seria colocada na pilha desse ator e a seguir seria executado o código de tratamento do serviço, ou seja:

  1. Seria extraído da tupla seu "último" número e colocado na pilha ( 10 é o tamanho do baralho)
  2. Seria ativada a agenda "gerarBaralho" (gerar um baralho com 10 cartas)
  3. O resultado (valor da variável baralho) seria enviado ao ator que emitiu o "perguntar".

É importante salientar que um serviço instalado com "sePerguntado" atende a todos os pedidos que lhe forem feitos. Se o serviço está ocupado, o pedido será colocado numa fila de pedidos pendentes, de onde será removido para atendimento. Essa é uma outra grande diferença entre um serviço com "sePerguntado" e um tratador de eventos instalado com o "seDito", pois um "seDito", como vimos, fica "surdo" (descarta os pedidos ocorridos) durante a execução do tratamento de um evento. O cadastramento inicial na fila de atendimento de um "sePerguntado" é feito no instante em que o cliente solicita o serviço. Portanto, se nesse instante o servidor não estiver ativo, o cliente não e" cadastrado. Ou seja: o serviço deve anteceder ao cliente.

Tenho dois atores e preciso que o ícone de um deles fique por cima do ícone do outro, como faço para isto acontecer?

Você deve alterar o atributo profundidade do ator com a primitiva fixarProfundidade da seguinte maneira:

umNúmero fixarProfundidade

A visibilidade será sempre relativa. Por exemplo: um ator com profundidade -5 será sobreposto por um ator com profundidade que será sobreposto por um ator com profundidade 0, que será sobreposto por um de profundidade 3.

Se dois atores tem o atributo profundidade idêntico, oque define qual ícone vai ficar por cima e qual vai ficar por baixo?

A ordem é definida pela ordem de instanciação dos atores, cada novo ator sobrepoem a imagem do antigo.

Como a ordem de instanciação dos atores é aleatória, a ordem dos ícones dos atores tambêm o será(a não ser que você faça um ator chamar outro em uma ordem determinada),

Como usar a primitiva desenhar poligono?

A primitiva desenhaPoligono serve para desenhar a borda de um poligono.

O desenho obedece a inclinação do ator, é como se o ator tivesse um sistema próprio de coordenadas que varia com sua direção, o eixo coordenado da abcissa ou o eixo "x" sempre aponta para a mesma direção do ator, ou seja:

Quando o ator estiver virado para 360/0 graus ele estara "em sintonia" com o sistema de coordenadas da tela:

360graus.png

Quando o ator está na direção padrão(90 graus) seu sistema de coordenadas será:

90graus.png

Alguns exemplos para o melhor entendimento desta primitiva:

http://telis.edugraf.ufsc.br/apliques/2005-1/TesteDesenharPoligono/TesteDesenhaPoligono/

Qual a diferença entre as agendas primitivas fixarIcone de fixarIconeGirável?

A primitiva fixarIconeGirável faz com que o ícone do ator acompanhe a inclinação do mesmo, a primitiva fixarIcone não.

Ou seja, quando você usar a primitiva fixarIconeGirável serão geradas todas as imagens necessárias, que correspondem às principais inclinações do ator (são dezenas).

As vezes você apenas quer mostrar uma imagem de fundo. Não vai girar nunca. Ou uma imagem de algo que apenas se desloca na tela, sem girar.

Para casos como esse, em que a imagem vai ser utilizada somente na posição original, NÂO se deve usar o fixarIconeGirável, e sim o fixarIcone.

Isso evita que Telis tenha de gerar todas as imagens internas, que travam o momento inicial da sua aplicação durante sua construção. Alêm disso, mesmo depois elas continuam consumindo muito espaço, pela forma com que são armazenadas (bitmap), oque pode ocasionar problemas de falta de memória(Out of Memory).

Para que serve a agenda primitiva @(atualValor)?

O arroba retorna o valor atual de uma váriavel.

Ou seja, se uma variável X está armazenando o valor 53, então @X vai ser igual a 53, neste caso ele não parece muito útil.

Mas, quando você precisa colocar o valor de uma variável numa lista isso é importante.

Imagine que voce quer enviar o atualValor de X pra outro ator, você não poderia usar:

[  X ] dizer

Pois seria enviado o simbolo X (e não o valor da variavel X) pois a regra geral de Telis é: dentro de lista, não avalie.

A saída seria avaliar o valor de X antes de enviar, oque é feito pela primitiva @(atualValor):

[ @X ]  dizer

Em resumo, pra isso serve a primitiva atualValor (o arroba). O arroba informa o Telis para não colocar na lista o simbolo X, mas sim o valor atual de X.

Como nomear variáveis dinâmicamente com Telis?

O problema é associar qualquer valor a qualquer texto.

A primitiva "associar" não serve, pois concatenando o texto na hora ele "se perde", não está "compilando" o novo texto, e por isso não reconhece o símbolo equivalente como uma variável.

A solução pode ser: criar uma agenda _associar, que faça isso, ela deve forçar a compilação do novo nome (executando uma lista de comandos).

Testes: A agenda deve respeitar as asserções abaixo

45 "x" _associar   
x 45 =

45 "x" "y" +  _associar
xy 45 =

45 "x" 1 comoTexto concatenar _associar
x1 45 =

Implementação:

"_associar"
   {recebe umValor e  umTextoParaNomeDeVariável na pilha - associa o valor à variável}
   [
   umNome associar umValor associar 
    [ @umValor @umNome associar ] executar 
   ]
incluirAgenda

Esta agenda e os testes estão publicados em: http://telis.edugraf.ufsc.br/apliques/2005-1/usa_associar/usa_associar.xml

É possível definir uma variável global em Telis?

A resposta é "não".

Não existe a idéia de variável global em Telis. as variáveis são "locais" ao ator a qual pertencem.

Essa é uma idéia-chave da noção de objeto, e importante em sistemas paralelos como Telis.

Além disso, a noção de "variável global" está ligada à existência de uma memória comum, compartilhada pelos atores,mas Telis foi feita pra rodar na Internet, com os atores distribuídos em várias máquinas (cada uma com sua memória própria).

Mas... "sim"

Você pode obter um efeito semelhante ao de variável global: Use a idéia de que atores são servidores: entidades que prestam serviços a outros atores.

E D U G R A F - Laboratório de Software Educacional - UFSC - CTC - INE
Campus Universitário - Trindade - Florianópolis - SC - Brasil 88040-090
Fone: +55 48 331 9735 / Fax: +55 48 331-9770
Última alteração deste tópico em 2007-02-16T20:53Z por PabloPolonia