"Constructors Considered Harmful" - Gilad Bracha

33 respostas
T

Em seu blog, Gilad Bracha argumenta que construtores devem ser considerados danosos, tanto quanto o “goto” (que foi considerado danoso há quase 40 anos atrás, por Edsger Dijkstra) e o “new” (há apenas 5 anos).

O que mais eles acharão danoso? (por favor, não ponham alusões a más condições de trabalho ou outras coisas. Limitem-se a construções das linguagens.)

33 Respostas

marciosantri

thingol:
Em seu blog, Gilad Bracha argumenta que construtores devem ser considerados danosos, tanto quanto o “goto” (que foi considerado danoso há quase 30 anos atrás, por Edsger Dijkstra) e o “new” (há apenas 5 anos).

O que mais eles acharão danoso? (por favor, não ponham alusões a más condições de trabalho ou outras coisas. Limitem-se a construções das linguagens.)

Sei lá. Será que se referiam à construtores fora dos padrões beans? hehehe
Falando sério, talvez seja porque construtores de classes filhas possam modificar alguma que a classe pai fosse fazer… Eu não entendi bem esse cara…

marciosantri

Só complementando, em alguns casos usaria sim métodos estáticos. Na maioria das vezes, não.

A

Ele tá falando que chamar um construtor diretamente em um objeto acopla demais duas classes, e que métodos estáticos mudam pouco a figura. Smalltalk tem metaclasses que são factory objects e permitem abstrair a construção de instâncias. Em contrapartida, metaclasses não garantem que a inicialização seja chamada uma vez (e só uma vez). Por fim ele diz que está trabalhando num sistema que resolve esse problema todo e vai publicar a proposta na ECOOP.

[Edit: A propósito, “Considered harmful” considered harmful"]

cv1

Pra adicionar na listinha de “considered harmful”:

  • Heranca (substituir por composicao)
  • Estado estatico (substituir por vergonha na cara)
  • Classes (substituir por prototipos)
neofito

cv:
Pra adicionar na listinha de “considered harmful”:

  • Heranca (substituir por composicao)
  • Estado estatico (substituir por vergonha na cara)
  • Classes (substituir por prototipos)

Sempre substituir herança por composição? Sei que se deve usar herança com muito cuidado, mas deixar de usá-la? Não há sequer um caso onde ela é útil?

pcalcado
  • Singleton por Fábricas que retornam o mesmo elemento (nos 0.00040343% das vezes que isso é encessário)
  • Métodos estáticos por um modelo de metaclasses decente

Mas não sei não, tô ansioso pela técnica.

L

Mas composição não tem um acoplamento muito forte?

cv1

Quando vc nao tem nem classes, como vc faz heranca? :wink:

Hal_Jordan

cv:
Pra adicionar na listinha de “considered harmful”:

  • Heranca (substituir por composicao)
    - Estado estatico (substituir por vergonha na cara)
  • Classes (substituir por prototipos)

:lol: :lol: :lol: :lol: :lol: :lol: :lol:

neofito

Quando vc nao tem nem classes, como vc faz heranca? ;)

Tudo bem, os “protótipos” aos quais você se refere é o mesmo que há em JavaScript? E como ficaria o polimorfismo nessa história? Só através de interfaces? Ou se a classe X não possuir um método Y, enfia um lá em tempo de execução?

Legal…

cv1

neofito, da uma olhada na io: http://www.google.com/search?q=iolanguage

Proteu_Alcebidiano

Quando vc nao tem nem classes, como vc faz heranca? ;)

As classes abertas, como vistas em ruby, tambem podem substituir heranca.

t+

Paulo_Silveira

Ok. Vou dar minha sugestao um tanto polemica.

Uma pergunta que muitos iniciantes novatos fazem é “porque nao posso declarar construtores e metodos estaticos em uma interface”. a resposta depois de um tempo fica obvia

mas agora, com generics, sempre pensei que declarar construtores na interface seria MUITO bom. motivo? injecao de dependencias e factories que nao sabem o que estao produzindo! e poder dar new SEM reflection

Olha so:

interface ConstructableWithRequest {
   ConstructableWithRequest(HttpServletRequest request);
}
class AlgumaCoisa implements ConstructableWithRequest  {
   // precisa ter o construtor aqui!
}

agora, o uso:

class FactorieDeConstructableWithRequest  {
   public <T extends ConstructableWithRequest> T fabrica(Class<T> c) {
     // considerando que teriamos reificacao dos generics:
      T t = new T(algumaServletRequest); // compila!!!
  }
}

nao parece lindo? Kumpera, Villela, Thingol, Ferreira, o que acham?

Fabio_Kung

Eu conheço um caso só: Template Method.

Mas que também pode ser facilmente substituído por um Decorator, então…

Proteu_Alcebidiano

thingol:
O que mais eles acharão danoso?

hum…penso que o termo ‘danoso’ se encaixa em qualquer conceito / comando que pode ser abstraida / esquecida-substituida por uma linguagem nativamente.

T+

cv1

Se nao tao planejando fazer isso no proximo round de mudancas na linguagem, eu quero meu dinheiro de volta :slight_smile:

Todo caso, joga isso no JCP e ve se vinga?

Ironlynx

É lindo!!! :smiley:

Apoiado!!!

pcalcado

Você quer tornar o construtor de uma classe parte do contrato? Não é mais fácil abolir construtores como sugere o Bracha?

Paulo_Silveira

Nao proponho uma solucao para acabar com a invocacao de construtores hardcoded, como o Gilad quer. Essa é uma proposta que retiraria containers de IOC de uma CENTENA de projetos pequenos que so querem dar um new dependendo dos construtores que ele tem, alem de ser totalmente compativel com a situacao atual da linguagem.

pcalcado

Ou não etnendi ou não estou convencido da utilidade disso. Em Java acho que ia piorar bastante a situação ao criar mocks, proxies e interceptors para AOP.

Mas, falando nisso: A maioria das reclamações é contra tipagem estática. Coincidência?

cv1

Nao entendi pq ia piorar a situacao pra quem usa mocks/proxies/cglib em geral. Pq, shoes?

Paulo_Silveira

Tambem nao entendi o problema em relacao a proxies dinamicas, os sistemas de mocks nao precisariam mockear isso, porque depois de instanciado pouco importa que construtores aquele objeto tem…

Proteu_Alcebidiano

pcalcado:

Mas, falando nisso: A maioria das reclamações é contra tipagem estática. Coincidência?

Sou a favor de linguagens que são capazes de assumir coisas que não preciso mais fazer explicitamente. Assim foi com as features que seduziam os developers a optarem por java ao invés de C++.

Com o tempo, acho que esse tipo de evolução não muda.

T+

pcalcado

Acho que entendi melhor agora… Vamos validar primeiro:

Uma interface é um contrato, quando se implementa uma interface se garante que o contrato foi estabelecido. Hoje em dia o contrato é composto apenas por métodos, a idéia é que a forma com que o objeto daquela classe é instanciado siga o contrato. O ponto de vocês é que como um proxy já foi instancaido por algum meio arcano não há como alguém chamar o construtor novamente, logo não haveria quebra de contrato.

Bom, há sim. Não sei se o sacrifício vale a pena , mas que há há :slight_smile:

Imagine que eu tenha a seguinte situação:

interface A{
 A(String arg);
}

E imagine que eu tenha um proxy vindo de alguma fonte obscura (CGLIB, DynamicProxy…os suspeitos usuais):

{
 A mamaeSouUmProxy = criaUmProxyQualquer(A.class, invokationHandlerXyz);
}

O seguinte trecho não é válido:

Class classeQueDeveriaConterOConstrutor = mamaeSouUmProxy.getClass();

Constructor oConstrutorQueNaoVaiExistirNesteCaso = classeQueDeveriaConterOConstrutor.getConstructor(new Class[]{String.class});

//CABOOOM

A umaInstanciaDamesmaClasse = oConstrutorQueNaoVaiExistirNesteCaso.invoke(new Object[]{"aiaiai"});

Correto?

Como falei não sei se os fins compensam os meios (ou se papei mosca em alguma coisa), mas eu sou geralmente a favor de uma linguagem coesa. Se não Java vira C# com suas 82 keywords e dezenas de exceções à regra.

Paulo_Silveira

voce entendeu e tem razao sim phillip. mas eh um caso beeeem particular e uma pequenina mudança pra quem quisesse suportar essa feature do java 12.

e sobre o c#, concordo.

A

Eu acho que um sistema de metaclasses decente resolveria o problema (eh soh a metaclasse implementar uma interface). Mas eu ainda fico em cima do muro se vale a pena jogar mais features e mudancas numa linguagem de 12 anos de idade e com zilhoes de linhas de codigo escritas e “em manutencao”.

(Ah, e pelo jeito outra mudanca linguistica que estou propondo eh abolir a acentuacao do portugues…)

ViniGodoy

Mais fraco do que a herança, certamente.

neofito

Valeu CV, vou dar uma olhada…

A

Olha so:

interface ConstructableWithRequest {
    ConstructableWithRequest(HttpServletRequest request);
 }
class AlgumaCoisa implements ConstructableWithRequest  {
    // precisa ter o construtor aqui!
 }

Isso não funciona

cv1

E no Brasil, gente assim anda nas mesmas ruas que voce, frequenta as mesmas lojas, parques, praças, bares, festas que voce. E, quer saber? Gente assim também vota.

bzanchet
A

O que vocês acham da proposta neste paper?

Kenobi

Paulo Silveira:
Ok. Vou dar minha sugestao um tanto polemica.

Uma pergunta que muitos iniciantes novatos fazem é “porque nao posso declarar construtores e metodos estaticos em uma interface”. a resposta depois de um tempo fica obvia

mas agora, com generics, sempre pensei que declarar construtores na interface seria MUITO bom. motivo? injecao de dependencias e factories que nao sabem o que estao produzindo! e poder dar new SEM reflection

Olha so:

interface ConstructableWithRequest {
   ConstructableWithRequest(HttpServletRequest request);
}
class AlgumaCoisa implements ConstructableWithRequest  {
   // precisa ter o construtor aqui!
}

agora, o uso:

class FactorieDeConstructableWithRequest  {
   public <T extends ConstructableWithRequest> T fabrica(Class<T> c) {
     // considerando que teriamos reificacao dos generics:
      T t = new T(algumaServletRequest); // compila!!!
  }
}

nao parece lindo? Kumpera, Villela, Thingol, Ferreira, o que acham?

Bom a adição só faz sentido se declarasse o construtor como private e alterasse a condição do new, como quer a propostahttp://www.ddj.com/dept/java/184405016;jsessionid=X3U4DFKCQJK2WQSNDLPCKH0CJUNN2JVN?_requestid=1462689

Caso contrário, não precisaria chamar a factory , isso seria somente um pattern…

Uma outra coisa que me incomoda são as facotries em pleno século 21, poderíamos usar outra abordagem, uma mais livre.

Como fica o esquema de testes do código ? Um saco …

Bom a proposta dos Singletons realmente pode ser uma saída.

Em Ruby poderíamos ter algo como :

class AlgumaCoisa
  private_class_method :new
  @@algumacoisa = nil
  def AlgumaCoisa.create
    @@ algumacoisa = new unless @@ algumacoisa
    @@ algumacoisa
  end
end


-------------

AlgumaCoisa.create.id  » 666
Criado 25 de junho de 2007
Ultima resposta 4 de jul. de 2007
Respostas 33
Participantes 16