Existe algum motivo para a inicialização lenta não poder ser incorporada ao Java?

10

Como estou trabalhando em um servidor com absolutamente nenhum estado não persistente para os usuários, todos os objetos relacionados ao usuário que temos são lançados a cada solicitação.

Consequentemente, frequentemente me vejo fazendo uma inicialização lenta de propriedades de objetos que podem não ser utilizados.

protected EventDispatcher dispatcher = new EventDispatcher();

Torna-se...

protected EventDispatcher<EventMessage> dispatcher;

public EventDispatcher<EventMessage> getEventDispatcher() {
    if (dispatcher == null) {
        dispatcher = new EventDispatcher<EventMessage>();
    }
    return dispatcher;
}

Existe alguma razão para isso não poder ser incorporado ao Java?

protected lazy EventDispatcher dispatcher = new EventDispatcher();


Como mencionado abaixo nos comentários, percebo que uma linguagem poderia evoluir teoricamente para incluir quase tudo o que você deseja. Estou procurando uma medida prática da possibilidade. Isso entraria em conflito com outros recursos? A implementação é simples o suficiente para funcionar bem com a JVM como ela existe? E mesmo, é uma boa ideia?

Nicole
fonte
2
não sei, mas exemplo de código não é thread-safe
Armand
2
@Alison, a synchronizedpalavra - chave funcionaria da mesma forma que se estivesse no método. Eu imagino que haveria alguma acomodação de métodos de construção mais complicados. No meu caso de uso específico , devido à natureza do problema, com cada solicitação como seu próprio mundo, a sincronização é inútil.
19611 Nicole
Em C #, o Lazy está em uma biblioteca, mas é suportado pelo idioma. sankarsan.wordpress.com/2009/10/04/laziness-in-c-4-0-lazyt O Java tem lambdas e delegados e encerramentos? By the way, você quer perguntar isso no SO, para que Jon Skeet & co. podem compartilhar sua sabedoria.
Job
3
Você pode criar praticamente tudo em qualquer idioma. Porém, o orçamento de complexidade e a lista de recursos são limitados e os designers de idiomas podem incluir apenas o que consideram mais importante (bem, exceto Larry Wall - especialmente no Perl 6, conhecido como "Todos os seus paradigmas são nossos").
11
O problema fundamental é que Java é a única linguagem de tipo estaticamente sem recurso de metaprogramação. Em C, você pode escrever isso como uma macro em dez minutos. Em C ++, você pode escrever isso como um modelo em cerca de dois minutos. Em Java, você pode ... colar e modificar.
Kevin cline

Respostas:

14

Aqui está uma resposta de oito páginas para sua pergunta: http://tinlizzie.org/~awarth/papers/fool07.pdf

Se eu posso tentar resumir grosseiramente os problemas com a adição de preguiça, são os casos de canto. Existem muitas advertências sobre os efeitos colaterais. Considere, no seu exemplo, se o construtor teve efeitos colaterais visíveis, como bater em um contador global ou executar E / S ... É difícil pensar em quando isso aconteceria. Ou considere os efeitos colaterais ainda mais feios sobre as exceções (elas são lançadas ... quando você faz referência ao objeto preguiçoso?)

Basta pular para a seção 6 no documento acima. (E admire toda a lógica formal do sistema de tipos nas páginas que você pula ...)

PT
fonte
Aceitando esta resposta devido à profundidade em que o artigo aborda esse recurso. Obrigado!
Nicole
TL; DR, ao programar, você precisa saber o que acontece para evitar efeitos colaterais, com preguiça, isso pode realmente ficar fora de controle. Se você conhece o Hibernate e quantos problemas algumas pessoas têm com ele, imagine o mesmo para todo o idioma.
Walfrat
10

Claro que é eminentemente possível. De fato, o scala já possui exatamente esse recurso! (Scala é uma linguagem da JVM e compila até o bytecode). Aqui está um pedaço da fonte scala:

class Foo {
  lazy val bar = "Hello World"
}

E aqui está a aparência de uma forma intermediária do código compilado:

scalac -Xprint:icode Foo.scala

[[syntax trees at end of icode]]// Scala source: Foo.scala
package <empty> {
  class Foo extends java.lang.Object with ScalaObject {
    @volatile protected var bitmap$0: Int = 0;
    lazy private[this] var bar: java.lang.String = _;
    <stable> <accessor> lazy def bar(): java.lang.String = {
      if (Foo.this.bitmap$0.&(1).==(0))
        {
          Foo.this.synchronized({
            if (Foo.this.bitmap$0.&(1).==(0))
              {
                Foo.this.bar = "Hello World";
                Foo.this.bitmap$0 = Foo.this.bitmap$0.|(1);
                ()
              };
            scala.runtime.BoxedUnit.UNIT
          });
          ()
        };
      Foo.this.bar
    };
    def this(): Foo = {
      Foo.super.this();
      ()
    }
  }

}

oxbow_lakes
fonte
Então, como isso se reconciliaria com a resposta da PT em programmers.stackexchange.com/a/110958/24257 ?
Pacerier
6

Eu acho que você primeiro precisa adicionar propriedades reais ao idioma Java, em vez de confiar no idioma getX / setX. Dessa forma, você pode simplesmente marcar a propriedade como preguiçosa (e sincronizada, somente leitura, etc ...).

Classifique o que é solicitado aqui (Objective-C, mas o conceito se aplica).

Martin Wickman
fonte
0

Obviamente, isso pode ser adicionado ao Java, a palavra-chave preguiçoso pode ser implementada como açúcar sintático. No entanto, se ele será implementado depende da visão dos construtores do compilador.

Michiel Overeem
fonte