[Prévia] [Próxima] [Prévia por assunto] [Próxima por assunto]
[Índice cronológico] [Índice de assunto]

Re: Exceções, interfaces e Java



On Thu, Apr 11 2002 at 12:43:31pm -0300, Jorge Francisco Del Teglia wrote:
 
> Isto é, parecem não existir restrições ao respeito de "relaxar" as
> exceções lançadas na classe implementadora. Ao contrario, SIM está
> prohibido lançar MAIS exceções que a interface/superclasse declara no
> método em questão.

La' no fim vou comentar isso ai', mas antes um pouco de papo-furado:

<rant mode>
<Alan Durham mode>
A questao aqui e' simples: Java, assim como C++, nao e' uma linguagem
orientada a objetos "pura"; essas linguagem sacrificam parte de sua
"pureza" em prol da checagem de tipos estrita em tempo de compilacao (o
que, supostamente, evita erros) e em prol da performance.

Em Smalltalk ("the one true OO-language"), um tipo e' definido por uma
interface; ou seja, dois objetos que tem a mesma interface tem o mesmo
tipo. Ponto. Final. Isso nao tem *nada* a ver com a arvore de hierarquias.
Uma classe define a *implementacao* de um tipo; uma classe B pode ser
derivada da classe A, mas as duas podem *nao ser* do mesmo tipo. Por outro
lado, duas classes que sao totalmente diferentes em termos de
implementacao mas que tem a mesma interface tem o mesmo tipo. Ou seja,
classes e tipos sao conceitos totalmente distintos: uma classe corresponde
apenas `a implementacao de um tipo, e a heranca serve para reutilizar o
codigo da implementacao de um tipo.

Em Java e C++, a coisa e' diferente: para nao haver o "overhead" que ha'
em smalltalk para "encontrar" um determinado metodo de um objeto qualquer,
o endereco do metodo na memoria do processo tem que ser conhecido em tempo
de compilacao; isso significa que nao e' possivel separar o tipo de sua
implementacao, ou seja, da classe. Em Java e C++, dois objetos que tem
exatamente a mesma interface so' sao do mesmo tipo se tambem pertencem a
uma mesma hierarquia de classes.

Nessas linguagens, existem dois tipos de heranca: a heranca de
implementacao, que e' a mesma que existe em smalltalk, onde a interface
"vem junto de brinde" (alias, em C++ (nao sei em Java), se voce fizer
heranca "private", a interface *nao* vem junto de brinde); e a heranca de
interface, onde, atraves da heranca, voce determina que duas classes
distintas implementam um mesmo tipo (nesse caso, pode ser que a
implementacao venha "de brinde"). Na pratica, na maioria dos casos
herda-se as duas coisas; so' nao e' assim no caso da derivacao "private"
(heranca so' de implementacao) e no caso de a superclasse ser puramente
abstrata ou uma "interface" java (heranca so' de interface).

Agora, como dois objetos so' podem ser do mesmo tipo se pertencerem a uma
mesma arvore de classes, e' meio obvio que se algum objeto tiver a
pretensao de ser de mais de um tipo, voce precisa de heranca multipla de
interface. E e' por isso que tanto C++ quanto java tem heranca multipla de
interface. Mas os desenvolvedores de java acharam que heranca multipla de
*implementacao* leva a problemas e, por isso, "disfarcaram": ao inves de
usar a sintaxe de C++, que sugere que as duas coisas sao possiveis,
"proibiram" a heranca multipla e inventaram a palavra reservada
"interface", que nada mais e' do que um mecanismo de permitir heranca
multipla apenas de interfaces. Por isso, diferentemente do que talvez poss
parecer, nao da' pra dizer que "C++ nao tem interfaces". C++ usa outra
sintaxe para fazer *exatamente* a mesma coisa, basta usar uma classe
puramente abstrata. Acontece que esse mecanismo e' uma "enganacao" para os
pobres programadores que nao usam Smalltalk acreditarem que programam em
uma linguagem orientada a objetos.
</rant mode>
</Alan Durham mode>

Bom, e o que diabos isso tem a ver com as excecoes e essas regras
"estranhas" que o Jorge falou? Muito simples: primeiro, e' bom lembrar que
quando voce usa o "throws" voce esta' definindo um "contrato" entre voce
(o desenvolvedor da classe) e o seu usuario (o usuario da sua classe),
onde voce diz: "esta e' a lista de todas as excecoes que este metodo pode
levantar". Voce faz isso para que o seu usuario possa escrever codigo
capaz de lidar com essas excecoes. No fundo, voce esta' definindo mais
"aspectos" da interface da sua classe e, portanto, do seu tipo.

Agora, seja uma superclasse A e sua subclasse B. B e' do tipo de A e,
portanto, B *precisa* poder interagir com outros objetos como se fosse um
objeto da classe A. Mas se B gerasse uma excecao que A nao geraria, a
coisa toda iria para o beleleu: voce poderia fazer um codigo lindo para
lidar com objetos do tipo A e cuidar de todas as excecoes possiveis, mas
esse codigo poderia falhar miseravelmente com um objeto da classe B. Como
Java prioriza a checagem em tempo de compilacao, essa situacao "esdruxula"
nao e' permitida pelo compilador: se isso fosse permitido, teriamos uma
situacao tal que dois objetos dentro de uma mesma hierarquia nao teriam de
fato a mesma interface (se considerarmos as excecoes como parte da
"interface"). Tenho a impressao que C++ e' mais "permissiva" nesse
quesito; talvez gere uns "warnings", mas acho que o codigo compila, mas
nao verifiquei.

Entao, pensando sob esse ponto de vista, fica facil de entender (e
lembrar!) dessas regrinhas.

Xau!