

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rodrigo Kumpera Weblog &#187; funcional</title>
	<atom:link href="http://www.kumpera.net/blog/index.php/tag/funcional/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kumpera.net/blog</link>
	<description>Meus achados sobre tecnologia</description>
	<lastBuildDate>Thu, 14 Jul 2011 15:45:23 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Herança não funciona</title>
		<link>http://www.kumpera.net/blog/index.php/2007/11/13/heranca-nao-funciona/</link>
		<comments>http://www.kumpera.net/blog/index.php/2007/11/13/heranca-nao-funciona/#comments</comments>
		<pubDate>Wed, 14 Nov 2007 02:18:39 +0000</pubDate>
		<dc:creator>kumpera</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[funcional]]></category>
		<category><![CDATA[linguagens]]></category>
		<category><![CDATA[OO]]></category>
		<category><![CDATA[teoria]]></category>

		<guid isPermaLink="false">http://www.kumpera.net/blog/index.php/2007/11/13/heranca-nao-funciona/</guid>
		<description><![CDATA[Por um bom tempo achei que eu não tinha entendido sobre o assunto, mas já posso afirmar categoricamente: Herança não funciona. Existe hoje substância e argumentos suficientes para sustentar essa afirmação. Antes de discutir o mérito do assunto já adianto óbvio, programação orientada-a-objetos é sim um paradigma que funciona &#8211; apenas que um de seus [...]]]></description>
			<content:encoded><![CDATA[<p>Por um bom tempo achei que eu não tinha entendido sobre o assunto, mas já posso afirmar categoricamente: Herança não funciona. Existe hoje substância e argumentos suficientes para sustentar essa afirmação. Antes de discutir o mérito do assunto já adianto óbvio, programação orientada-a-objetos é sim um paradigma que funciona &#8211; apenas que um de seus elementos não funciona como se esperava. No fundo quem já programou em Java, C#, Ruby ou Smalltalk já sentiu que existe algo de estranho nessas linguagens, algo que não parece certo, e herança é o denominador comum desse sentimento.</p>
<p>
O problema que vou tentar aqui descrever já foi estudado pelo Luca Cardelli, que é a questão da co-variância e contra-variância dos tipos &#8211; um problema que só existe na presença de herança.  Originalmente foi descoberto quando ele tentou formular um cálculo para linguagens OO, algo análogo ao cálculo lambda para linguagens funcionais, e somente conseguiu progredir quando tentava reduzir para calculo lambda sem tipagem. Abandono aqui qualquer tentativa de equacionar a questão e explico a seguir através de exemplos. Vou comentar sobre a consistencia de sistemas de tipos, parametricidade de tipos e transparência de refêrencia.</p>
<p>A principal característica da herança é poder substituir um tipo mais abstrato por um mais especializado, poder trocar <em>object</em> por <em>string</em>, e não estar assim violando o sistema de tipos. Dada uma variável do tipo A, definimos operações de leitura e escrita. Para a leitura podemos dizer que o tipo retornado é A ou um super tipo de A; e para a escrita podemos dizer que o tipo aceito é A ou um sub tipo de A*. Exemplificando, se temos C&lt;B&lt;A (C estende B que estende A), uma variável do tipo B pode ser atribuída o objeto de tipos B ou C, enquanto podemos considerar que os tipos lidos são sempre A ou B.</p>
<p>* Normalmente consideramos que A é super tipo e sub tipo de si próprio, logo leitura retorna um super tipo e escrita aceita um sub tipo.</p>
<p>Linguagens tipadas são assim e funcionam, então onde está o problema? O problema existe quando queremos ter referências para estas variáveis, C++ e C# são linguagens que suportam esse recurso. Vamos supor que referências a variaveis também funcionem com herança, isto é, uma referência à A pode ser substituída por uma à B. Vamos então examinar o pseudo-código abaixo:</p>
<p><code><br />
C<B<A //C estende B que estende A<br />
D<A //D estende A</p>
<p>void foo (A &#038;a) {<br />
  a = new D();<br />
}</p>
<p>A a;<br />
B b;</p>
<p>A &#038;ra = &#038;a; //ra é uma referencia à variável 'a'<br />
B &#038;rb = &#038;b; //ra é uma referencia à variável 'b'</p>
<p>foo (ra); // #1<br />
foo (rb); // #2<br />
</code></p>
<p>Em #1, tudo ocorre corretamente pois a C é um sub tipo de A, condição exigida pela operação de escrita. Porém em #2, isso não ocorre, já que C não é sub tipo de B. Nesta situação temos uma clara falha no sistema de tipos e o comportamento durante a execução é imprevisível. Poderíamos inverter a direção da herança de referências, isto é, A&#038; é um sub tipo de B&#038; e desta forma resolveríamos o problema do exemplo anterior. Porém não sem introduzir semelhante situação quando tivermos leitura. Este é o exemplo mais simples para demonstrar o problema da co-variância da leitura e da contra-variância da escrita.</p>
<p>Tendo visto esta questão, entender o problema com tipo paramétricos e simples. A grosso modo, tipos paramétricos é o termo que a comunidade de linguagens funcionais usa para generics. Um tipo paramétrico não consegue carregar para si o relacionamento de herança que existe entre seus parâmetros pois, como vimos antes, não é possível estabelecer uma relação de herança para as variáveis parametrizadas do tipo - por isso que <em>List&lt;String&gt;</em> não tem como ser um sub-tipo de <em>List&lt;Object&gt;</em>.</p>
<p>Uma solução parcial para é utilizar os <em>wildcards</em> do Java, que permite definir qual variância será utilizada. Solução similar é possível utilizando métodos genéricos em C# ou Java. Em ambos os caso, porém, não é possível definir código que ao mesmo tempo tem papel de escrita e leitura - além de criar assinaturas de métodos completamente assustadoras como as encontradas em <em>java.util.Collections</em>.</p>
<p>Por fim venho com a questão da consistencia do sistema de tipos, que deveria garantir que todas operações sobre tipos não deveriam falhar ou gerar estado inconsistente, salvo aquelas que testam explicitamente por um tipo como <em>casts</em>, <em>is/as</em> (C#) e <em>instanceof</em> (Java). Infelizmente não existe consistencia no sistema de tipos em linguagens como Java ou C#, que admitem herança entre <em>arrays</em>. Um atribuição a uma posição de um <em>array</em> pode falhar com <em>ArrayStoreException/ArrayTypeMismatchException</em>. Isso ocorre pois um <em>array</em> não é nada além que um vetor de referências e já sabemos que referências e herança não casam.</p>
<p>O mais curioso deste assunto é que não falo de um assunto que já não sabíamos, sinais claros existem vários: recomenda-se utilizar composição no lugar de estensão, frameworks baseados em herança são notoriamente mais difíceis de usar, a maioria dos sistemas hoje são modelados utilizando interfaces explicitas ou meta interfaces*.  Quanto  a solução, se  ela se resume a apenas  eliminarmos herança, não  clamo por  sabê-la. Digo, entretanto, que existem várias técnicas que compensam sua ausência e pretendo explorá-las em artigos futuros.</p>
<p>*Chamo aqui de meta interfaces aquelas que são frutos de conversão (JavaBeans) ou anotação (EJB3).</p>
<p><strong>Update:</strong> apenas pequenas correções no texto. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kumpera.net/blog/index.php/2007/11/13/heranca-nao-funciona/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
	</channel>
</rss>

