A new
palavra-chave em linguagens como Java, Javascript e C # cria uma nova instância de uma classe.
Essa sintaxe parece ter sido herdada do C ++, onde new
é usada especificamente para alocar uma nova instância de uma classe na pilha e retornar um ponteiro para a nova instância. No C ++, essa não é a única maneira de construir um objeto. Você também pode construir um objeto na pilha, sem usar new
- e, de fato, essa maneira de construir objetos é muito mais comum em C ++.
Portanto, vindo de um background em C ++, a new
palavra - chave em linguagens como Java, Javascript e C # parecia natural e óbvia para mim. Então comecei a aprender Python, que não tem a new
palavra - chave. No Python, uma instância é construída simplesmente chamando o construtor, como:
f = Foo()
No começo, isso me pareceu um pouco complicado, até que me ocorreu que não havia razão para o Python ter new
, porque tudo é um objeto, então não há necessidade de desambiguar as várias sintaxes dos construtores.
Mas então eu pensei - qual é realmente o sentido disso new
em Java? Por que deveríamos dizer Object o = new Object();
? Por que não apenas Object o = Object();
? No C ++, há definitivamente uma necessidade new
, pois precisamos distinguir entre alocar na pilha e alocar na pilha, mas em Java todos os objetos são construídos na pilha, então por que ter a new
palavra - chave? A mesma pergunta pode ser feita para Javascript. Em C #, com o qual estou muito menos familiarizado, acho que new
pode ter algum objetivo em termos de distinguir entre tipos de objeto e tipos de valor, mas não tenho certeza.
Independentemente disso, parece-me que muitas linguagens que vieram depois do C ++ simplesmente "herdaram" a new
palavra-chave - sem realmente precisar dela. É quase como uma palavra-chave vestigial . Parece que não precisamos dele por nenhum motivo, e ainda está lá.
Pergunta: Estou correto sobre isso? Ou existe algum motivo convincente que new
precisa estar em linguagens gerenciadas por memória inspiradas em C ++, como Java, Javascript e C #, mas não Python?
fonte
new
palavra - chave? Claro que quero criar uma nova variável, compilador estúpido! A boa linguagem seria, em minha opinião tem uma sintaxe comof = heap Foo()
,f = auto Foo()
.f
não escapar da função, aloque espaço na pilha.f
quando a função envolvente retornar.Respostas:
Suas observações estão corretas. C ++ é uma fera complicada, e a
new
palavra - chave foi usada para distinguir entre algo que precisavadelete
mais tarde e algo que seria recuperado automaticamente. Em Java e C #, eles soltaram adelete
palavra - chave porque o coletor de lixo cuidaria dela por você.O problema então é por que eles mantiveram a
new
palavra - chave? Sem falar com as pessoas que escreveram o idioma, é meio difícil de responder. Meus melhores palpites estão listados abaixo:new
palavra - chave cria um objeto no heap. Então, por que mudar o comportamento esperado?Ruby está em algum lugar entre Python e Java / C # em seu uso
new
. Basicamente, você instancia um objeto como este:Não é uma palavra-chave, é um método estático para a classe. O que isso significa é que, se você quiser um singleton, poderá substituir a implementação padrão
new()
para retornar sempre a mesma instância. Não é necessariamente recomendado, mas é possível.fonte
alloc
método (aproximadamente o mesmo que o de Rubynew
) também é apenas um método de classe.Em suma, você está certo. A palavra-chave new é supérflua em linguagens como Java e C #. Aqui estão algumas idéias de Bruce Eckel, que era membro do C ++ Standard Comitee na década de 1990 e depois publicou livros sobre Java: http://www.artima.com/weblogs/viewpost.jsp?thread=260578
fonte
var
palavra-chave não é nem de longe tão boa quantoauto
em C ++, mas espero que melhore.Há duas razões pelas quais posso pensar:
new
distingue entre um objeto e um primitivonew
sintaxe é um pouco mais legível (IMO)O primeiro é trivial. Não acho que seja mais difícil diferenciar os dois. O segundo é um exemplo do argumento do OP, que é meio que
new
redundante.Porém, pode haver conflitos de namespace; considerar:
Você poderia, sem muito esforço da imaginação, facilmente terminar com uma ligação infinitamente recursiva. O compilador precisaria aplicar um erro "Nome da função igual ao objeto". Isso realmente não faria mal, mas é muito mais simples de usar
new
, o que afirma queGo to the object of the same name as this method and use the method that matches this signature.
Java é uma linguagem muito simples de analisar, e suspeito que isso ajude nessa área.fonte
Java, por exemplo, ainda tem a dicotomia de C ++: não muito tudo é um objeto. Java possui tipos internos (por exemplo,
char
eint
) que não precisam ser alocados dinamicamente.Isso não significa que isso
new
seja realmente necessário em Java - o conjunto de tipos que não precisam ser alocados dinamicamente é fixo e conhecido. Quando você define um objeto, o compilador pode saber (e, de fato, sabe) se é um valor simples quechar
ou um objeto que precisa ser alocado dinamicamente.Eu evitarei (mais uma vez) opinar sobre o que isso significa sobre a qualidade do design do Java (ou a falta dele, conforme o caso).
fonte
new
, portanto, esse não é realmente o motivo.Em JavaScript, você precisa disso porque o construtor se parece com uma função normal; então, como o JS deve saber que deseja criar um novo objeto, se não fosse a nova palavra-chave?
fonte
Curiosamente, VB faz necessário - a distinção entre
que declara uma variável sem atribuí-la, o equivalente
Foo f;
em C # eque declara a variável e atribui uma nova instância da classe, o equivalente
var f = new Foo();
em C #, é uma distinção substantiva. No pré-.NET VB, você poderia usarDim f As Foo
ouDim f As New Foo
- porque não havia sobrecarga nos construtores.fonte
Dim f As Foo()
declara uma matriz deFoo
s. Oh alegria! :-)Dim Foo As New Bar
efetivamente criariaFoo
uma propriedade que construiria aBar
se fosse lida enquanto (ieNothing
). Esse comportamento não se limitou a acontecer uma vez; definindoFoo
aNothing
e, em seguida, lê-lo criaria um outro novoBar
.Eu gosto de muitas respostas e gostaria de acrescentar isso:
facilita a leitura do código
Não que essa situação aconteça com frequência, mas considere que você queira um método no nome de um verbo que compartilhe o mesmo nome que um substantivo. C # e outro idioma naturalmente têm a palavra
object
reservada. Mas, se não fosse, seriaFoo = object()
o resultado da chamada do método de objeto ou instanciaria um novo objeto. Esperemos que a linguagem sem anew
palavra-chave tenha proteções contra essa situação, mas ao ter o requisito danew
palavra - chave antes da chamada de um construtor, você permite a existência de um método com o mesmo nome que um objeto.fonte
Há muitas coisas vestigiais em muitas linguagens de programação. Às vezes, existe por design (o C ++ foi projetado para ser o mais compatível possível com o C); às vezes, está lá. Para um exemplo mais flagrante, considere até que ponto a
switch
instrução C quebrada se propagou.Eu não sei Javascript e C # bem o suficiente para dizer, mas não vejo razão para isso
new
em Java, exceto pelo C ++.fonte
x = new Y()
no JavaScript não instancia aY
classe, porque o JavaScript não tem classes. Mas parece Java, e leva anew
palavra - chave adiante do Java, o que, é claro, a frente do C ++.Em C #, permite tipos visíveis em contextos onde, de outra forma, poderiam ser obscurecidos por um membro. O permite que você tenha uma propriedade com o mesmo nome que seu tipo. Considere o seguinte,
Observe que o uso de
new
permite que fique claro queAddress
esseAddress
tipo não é oAddress
membro. Isso permite que um membro tenha o mesmo nome que seu tipo. Sem isso, você precisaria prefixar o nome do tipo para evitar a colisão de nomes, comoCAddress
. Isso foi muito intencional, pois Anders nunca gostou da notação húngara ou de algo semelhante e desejou que o C # fosse utilizável sem ela. O fato de também ser familiar era um bônus duplo.fonte
Curiosamente, com o advento do encaminhamento perfeito, a não colocação
new
também não é necessária em C ++. Portanto, sem dúvida, não é mais necessário em nenhum dos idiomas mencionados.fonte
std::shared_ptr<int> foo();
terá que ligar denew int
alguma forma.Não tenho certeza se os designers de Java tinham isso em mente, mas quando você pensa em objetos como registros recursivos , você pode imaginar que
Foo(123)
não retorna um objeto, mas uma função cujo ponto de correção é o objeto que está sendo criado (ou seja, função que retornaria o objeto se for dado como argumento o objeto que está sendo construído). E o objetivo denew
é "dar um nó" e retornar esse ponto fixo. Em outras palavrasnew
, tornaria o "objeto a ser" ciente dissoself
.Esse tipo de abordagem pode ajudar a formalizar a herança, por exemplo: você pode estender uma função de objeto com outra função de objeto e, finalmente, fornecer a eles comum
self
usandonew
:Aqui
&
combina duas funções de objeto.Nesse caso,
new
pode ser definido como:fonte
Permitir 'nulo'.
Juntamente com a alocação baseada em heap, o Java adotou o uso de objetos nulos. Não apenas como um artefato, mas como um recurso. Quando os objetos podem ter um estado nulo, é necessário separar a declaração da inicialização. Daí a nova palavra-chave.
Em C ++, uma linha como
Chamaria instantaneamente o construtor padrão.
fonte
Person me = Nil
ou ter oPerson me
Nil por padrão e usarPerson me = Person()
para não-Nil? O que quero dizer é que não parece que Nil tenha sido um fator nessa decisão ...Person me
sendo nulo ePerson me()
invocando o construtor padrão. Portanto, você sempre precisará de parênteses para invocar qualquer coisa e, assim, livrar-se de uma irregularidade em C ++.A razão pela qual o Python não precisa disso é por causa do seu sistema de tipos. Fundamentalmente, quando você vê
foo = bar()
no Python, não importa sebar()
é um método que está sendo chamado, uma classe que está sendo instanciada ou um objeto functor; em Python, não há diferença fundamental entre um functor e uma função (porque métodos são objetos); e você pode até argumentar que uma classe sendo instanciada é um caso especial de um functor. Portanto, não há razão para criar uma diferença artificial no que está acontecendo (especialmente porque o gerenciamento de memória é extremamente oculto no Python).Em uma linguagem com um sistema de digitação diferente, ou na qual métodos e classes não são objetos, existe a possibilidade de uma diferença conceitual mais forte entre criar um objeto e chamar uma função ou functor. Portanto, mesmo que o compilador / intérprete não precise da
new
palavra-chave, é compreensível que ela seja mantida em linguagens que não quebraram todos os limites do Python.fonte
Na verdade, em Java, há uma diferença ao usar Strings:
é diferente de
Supondo que a string
"myString"
nunca tenha sido usada antes, a primeira instrução cria um único objeto String no pool de String (uma área especial da pilha) enquanto a segunda instrução cria dois objetos, um na área de heap normal para objetos e outro no pool de String . É bastante óbvio que a segunda declaração é inútil nesse cenário específico, mas é permitida pelo idioma.Isso significa que new garante que o objeto seja criado nessa área especial do heap, alocado para instanciação normal do objeto, mas pode haver outras maneiras de instanciar objetos sem ele; o exemplo acima é um exemplo e há espaço para extensibilidade.
fonte
String myString = String("myString");
?" (observe a ausência danew
palavra - chave)class MyClass { public MyClass() {} public MyClass MyClass() {return null;} public void doSomething { MyClass myClass = MyClass();}} //which is it, constructor or method?
String
contraria as convenções de estilo Java, portanto, você pode assumir que qualquer método que comece com maiúsculas é um construtor. E segundo, se não somos constrangidos pelo Java, o Scala tem "classes de casos" em que o construtor se parece exatamente como eu disse. Então onde está o problema?new
para idiomas gerenciados . Eu mostrei que issonew
não é de todo necessário (por exemplo, Scala não é necessário para as classes de casos) e também que não há ambiguidade (já que você absolutamente não pode ter um método nomeadoMyClass
na classeMyClass
). Não há ambiguidade paraString s = String("hello")
; não pode ser outra coisa senão um construtor. E, finalmente, discordo: as convenções de código existem para aprimorar e esclarecer a sintaxe, sobre a qual você está discutindo!new
palavra - chave porque, caso contrário, a sintaxe do Java teria sido diferente"? Tenho certeza que você pode ver a fraqueza desse argumento;) E sim, você continua discutindo sintaxe, não semântica. Além disso, compatibilidade retroativa com o quê? Se você estiver projetando uma nova linguagem, como Java, já é incompatível com C e C ++!Em C #, new é importante distinguir entre objetos criados na pilha versus a pilha. Criamos frequentemente objetos na pilha para melhor desempenho. Veja, quando um objeto na pilha fica fora do escopo, ele desaparece imediatamente quando a pilha se desfaz, exatamente como um primitivo. Não é necessário que o coletor de lixo o controle e não há sobrecarga extra do gerenciador de memória para alocar o espaço necessário no heap.
fonte