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:
- nome deste ator (ator tangível que emitiu o estímulo)
- identidade deste ator (numero que o identifica, não importando assim quantos atores tem o mesmo nome)
- nome do outro ator
- identidade do outro ator
- posição deste ator
- posição do outro ator
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:
- Seria extraído da tupla seu "último" número e colocado na pilha ( 10 é o tamanho do baralho)
- Seria ativada a agenda "gerarBaralho" (gerar um baralho com 10 cartas)
- 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:
Quando o ator está na direção padrão(90 graus) seu sistema de coordenadas será:
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.