A POO pode ser usada em Tcl (até a versão 8.5) com o uso de pacotes de extensão tais como: IncrTcl, XOTcl, Snit e TclOO.
A partir da Tcl 8.6 o TclOO vem incorporado ao interpretador. Por isso procurei informações sobre TclOO no Wiki Tcl/Tk e encontrei no link http://wiki.tcl.tk/18152, o qual sugere o uso do Teacup ou o pacote do TclOO do Sourceforge.
Resolvi baixar o pacote 0.6 do TclOO Sourceforge.
Baixei, descompactei com o comando:
tar
-xzvf
TclOO0.6.tar.gz
Entrei no diretório TclOO0.6
e seguindo as informações do README.txt
executei o comando:
$ ./configure checking for correct TEA configuration... ok (TEA 3.6) checking for Tcl configuration... configure: WARNING: Can't find Tcl configuration definitions
No site http://cep.xor.aps.anl.gov/specfe/x712.html encontrei a solução para este problema. Bastou localizar o arquivo tclConfig.sh
e rodar o comando anterior com a opção --with-tcl=/usr/lib/tcl8.5/
./configure --with-tcl=/usr/lib/tcl8.5/ checking for correct TEA configuration... ok (TEA 3.6) checking for Tcl configuration... found /usr/lib/tcl8.5/tclConfig.sh checking for existence of /usr/lib/tcl8.5/tclConfig.sh... loading ... ... checking for tclsh... /usr/bin/tclsh8.5 checking for sdx... none checking for sdx.kit... none configure: WARNING: cannot find sdx; building starkits will fail configure: building as a normal library still supported configure: creating ./config.status config.status: creating Makefile config.status: creating tclooConfig.sh config.status: creating config.h
Dei uma olhada nas mensagens exibidas pelo comando e me chamou atenção a falta dos aplicativos para Starkit.
checking for sdx... none checking for sdx.kit... none configure: WARNING: cannot find sdx; building starkits will fail
Starkit é uma ferramenta muito útil pois permite empacotar o script principal e bibliotecas em um único arquivo que pode ser executado pelo interpretador da ActiveTcl ou pelo interpretador Tclkit.
O Starkit pode ser combinado com o Tclkit em um único pacote executável chamado Starpack, que pode ser usado sem a necessidade de descompactação ou instalação.
O Tclkit também já oferece suporte nativo para POO com a IncrTcl.
Resolvi continuar a instalação do TclOO e deixar para mais tarde a instalação do Starkit e IncrTcl.
Em seguida executei make -> make test e como root executei make install
.
Pela saída do comando make install
pode-se verificar que o arquivo pkgIndex.tcl
foi instalado no diretório /usr/lib
Para verificar se o pacote está funcionando rodar o tclsh em um terminal e testar:
% package require TclOO 0.6
Vamos começar criando uma classe simples chamada Contador
que permitirá incrementar, retornar o valor atual e zerar (reiniciar). (Fonte: Tcl 8.5 Networking Programming, 2010)
#!/usr/bin/env tclsh #Exemplo de uma classe package require TclOO oo::class create Contador { constructor {} { my ZerarContador } method ZerarContador {} { #mapeia a variável c como variável local e define o conteúdo como 0 my variable c set c 0 } method incrementar {} { #mapeia a variável c como variável local e incrementa my variable c incr c } method retornarvalor {} { #retornar valor corrente my variable c return $c } } #Teste set c1 [Contador new] set c2 [Contador new] puts "c1 = $c1 e c2 = $c2 \n" $c1 incrementar $c2 incrementar $c1 incrementar puts [$c1 retornarvalor] puts [$c2 retornarvalor]
O comando package require TclOO
carrega o pacote TclOO e em seguida a linha oo::class create Contador
cria uma classe chamada Contador
e define um construtor que chama o método ZerarContador para zerar o conteúdo.
... package require TclOO oo::class create Contador { constructor {} { my ZerarContador } ...
O comando my, usado na criação do método ZerarContadordefine o método ZerarContador como um método “privado”. E o comando my variable é usado para mapear a variável de um objeto específico como uma variável local, e portanto my variable c
faz com que a variável c (específica de um objeto) se torne disponível para um método específico.
O método incrementar aumenta o valor do Contador e o método retornarvalor retorna o valor do Contador.
Para testar o uso da classe foram criados dois objetos da classe Contador com o comando
[ Nome_da_Classe ] new
o qual retorna um identificador único que é armazenado na variável c1 e c2 respectivamente.
set c1 [Contador new] set c2 [Contador new]
Os conteúdos são exibidos com o comando puts [$c1 retornarvalor], em seguida são incrementados ($c1 incrementar) e novamente exibidos.
puts [$c1 retornarvalor] puts [$c2 retornarvalor] $c1 incrementar $c2 incrementar $c1 incrementar puts [$c1 retornarvalor] puts [$c2 retornarvalor]
No final os objetos são removidos da memória com o comando destroy.
Os objetos também podem ser criados com a sintaxe
[ Nome_da_Classe ] create
[ Nome_do_Objeto ]
, e o teste do programa anterior poderia ser escrito como:
... Contador create c1 Contador create c2 puts [c1 retornarvalor] puts [c2 retornarvalor] c1 incrementar c2 incrementar puts [c1 retornarvalor] puts [c2 retornarvalor] c1 destroy c2 destroy
Um outro método poderia ser definido para objetos da classe Contador
com os comandos:
oo::define Contador { method defvalor {valor} { my variable c set c $valor } } ou oo::define Contador method defvalor {valor} { my variable c set c $valor }
Podemos criar classes que herdam as características de outras classes.
Por exemplo, podemos criar uma classe Contador_zero
(classe filho)que herda as características da classe Contador
(classe pai) mas com a diferença de poder zerar o Contador após cada leitura.
oo::class create Contador_zero { #Declara a classe Contador como superclasse superclass Contador method retornarvalor {} { #obtem o resultado da classe Contador set result [next] my ZerarContador return $result } }
E para testar o código com os comandos:
Contador_zero create c0 puts [c0 retornarvalor] c0 incrementar puts [c0 retornarvalor] puts [c0 retornarvalor]
Em TclOO o comando superclass Contador
declara a classe Contador
como a superclasse da nova classe Contador_zero
.
Com a linha method retornarvalor {} { estamos sobrescrevendo o método retornarvalor que passa a ter um novo comportamento quando for chamado pelos objetos da classe Contador_zero
.
A linha set result [next] utiliza o comando next o qual executa o método retornarvalor “da classe Contador
” e atribui o resultado à variável result
.
E em seguida é executado o método ZerarContador com o comando my pois se trata de um método privado.
Métodos Privados realizam tarefas ou processam informações que dizem respeito apenas ao funcionamento interno da classe em questão.
Por exemplo, se você tenter acessar (executar) o método ZerarContador com o comando c1 ZerarContador receberá uma mensagem de erro:
unknown method "ZerarContador": must be defvalor, destroy, incrementar or retornarvalor while executing "c1 ZerarContador"
O pacote TclOO permite que os métodos sejam chamados de dentro do objeto ( my [nome_do_método]) e de fora do objeto ( c1 [nome_do_método] ). Mas esse comportamento pode ser modificado com o uso dos comandos export e unexport na definição da classe.
Por exemplo, podemos criar uma classe (Ex: Contador_tempo
que não permite o método incrementar seja chamado de fora do objeto.
oo::class create Contador_tempo { superclass Contador constructor {} { #Implementar alguma rotina para incrementar o contador #em intervalos periódicos } unexport incrementar }
Também é possível uma classe herdar as características de várias outras classes, especificando mais de uma superclasse.
Neste caso os métodos chamados são procurados em todas as superclasses, e se um método está implementado em mais de uma classe, a escolha do método a ser executado será feita com base na ordem em que as classes foram especificadas.
oo::class create Classe_teste { method retornarvalor {} { puts "Método retornarvalor da Classe_teste" next } } oo::class create Contador_teste { superclass Classe_teste Contador }
Por exemplo, quando o método retornarvalor for chamado por um objeto da classe Contador_teste
, será executado primeiramente o método da classe Classe_teste
que exibe no terminal a mensagem Método retornarvalor da Classe_teste
e em seguida o comando next executa o método retornarvalor da classe Contador
.
O comando next também pode ser usado com parâmetros quando o método chamado exigir argumentos.
O comando oo::objdefine permite editar o código de um método para um objeto específico.
oo::objdefine c1 { method retornarvalor {} { puts "Executando o método retornarvalor para o objeto c1" next } }
No exemplo anterior foi acrescentado o comando puts "Executando..."
ao método retornarvalor apenas para o objeto c1
. E o comando next chama a execução do método retornarvalor original (da classe Contador
).