Por que a maioria das linguagens de programação possui palavras-chave ou sintaxe especiais para declarar funções? [fechadas]

39

A maioria das linguagens de programação (linguagens de tipo dinâmico e estaticamente) possui palavras-chave e / ou sintaxe especiais que parecem muito diferentes do que declarar variáveis ​​para declarar funções. Vejo funções como apenas declarar outra entidade nomeada:

Por exemplo, em Python:

x = 2
y = addOne(x)
def addOne(number): 
  return number + 1

Por que não:

x = 2
y = addOne(x)
addOne = (number) => 
  return number + 1

Da mesma forma, em uma linguagem como Java:

int x = 2;
int y = addOne(x);

int addOne(int x) {
  return x + 1;
}

Por que não:

int x = 2;
int y = addOne(x);
(int => int) addOne = (x) => {
  return x + 1;
}

Essa sintaxe parece uma maneira mais natural de declarar algo (seja uma função ou uma variável) e uma palavra-chave a menos como defou functionem alguns idiomas. E, na IMO, é mais consistente (eu procuro o mesmo local para entender o tipo de uma variável ou função) e provavelmente torna o analisador / gramática um pouco mais simples de escrever.

Eu sei que muito poucas linguagens usam essa ideia (CoffeeScript, Haskell), mas as linguagens mais comuns têm sintaxe especial para funções (Java, C ++, Python, JavaScript, C #, PHP, Ruby).

Mesmo em Scala, que suporta os dois lados (e tem inferência de tipo), é mais comum escrever:

def addOne(x: Int) = x + 1

Ao invés de:

val addOne = (x: Int) => x + 1

Na IMO, pelo menos em Scala, essa é provavelmente a versão mais facilmente compreensível, mas esse idioma raramente é seguido:

val x: Int = 1
val y: Int = addOne(x)
val addOne: (Int => Int) = x => x + 1

Estou trabalhando na minha própria linguagem de brinquedos e estou me perguntando se há alguma armadilha se eu projetar minha linguagem dessa maneira e se há alguma razão histórica ou técnica, esse padrão não é amplamente seguido.

pathikrit
fonte
9
O motivo é provavelmente histórico. Quem fez primeiro fez dessa maneira, e todos os outros copiaram. Mas duvido que possamos ter certeza.
29
Eu acho que é porque uma função ou método simplesmente não é apenas outra entidade nomeada . Em linguagens funcionais, elas são (você pode distribuí-las etc.), mas em outras linguagens (como Java) uma função ou método é algo completamente diferente de uma variável simples e não pode ser tratado como tal (admito que o Java 8 enfraquece isso ), então faz sentido definir funções / métodos de maneira diferente, pois eles se comportam de maneira diferente.
11684
15
Discordo que sua proposta é uma maneira mais natural de declarar funções. Eu realmente não gosto da sintaxe do Coffeescript e parte disso tem a ver com a sintaxe da declaração de função. O fato é que, se não estiver quebrado, não conserte. Escrever 'def' ou 'function' não é grande coisa e é muito mais óbvio do que um olhar em comparação com alguns símbolos extravagantes do tipo Perl que, com olhos impensados ​​ou cansados, poderiam facilmente ser confundidos com outra coisa. Em uma observação completamente pessoal, também acho que a sintaxe sugerida nos exemplos parece muito mais feia do que a sintaxe atual.
Roy
22
Como '=>' não é uma "palavra - chave ou sintaxe especial para declarar uma função"?
TML 28/09
11
Eu não sei sobre você, mas para mim (int => int) addOne = (x) => {é muito mais "especial" e "complexo" do que int addOne(int) {...
Bogdan Alexandru

Respostas:

48

Penso que a razão é que a maioria das linguagens populares provém ou foram influenciadas pela família C de línguas, em oposição às linguagens funcionais e sua raiz, o cálculo lambda.

E nessas linguagens, funções não são apenas outro valor:

  • Em C ++, C # e Java, você pode sobrecarregar funções: você pode ter duas funções com o mesmo nome, mas com assinatura diferente.
  • Em C, C ++, C # e Java, você pode ter valores que representam funções, mas ponteiros de função, functores, delegados e interfaces funcionais são todos distintos das próprias funções. Parte do motivo é que a maioria delas não são apenas funções, elas são uma função juntamente com algum estado (mutável).
  • Variáveis são mutáveis por padrão (você tem que usar const, readonlyou finalpara proibir mutação), mas funções não podem ser realocados.
  • De uma perspectiva mais técnica, código (que é composto de funções) e dados são separados. Eles normalmente ocupam partes diferentes da memória e são acessados ​​de maneira diferente: o código é carregado uma vez e depois executado apenas (mas não é lido ou gravado), enquanto os dados são frequentemente constantemente alocados e desalocados e estão sendo gravados e lidos, mas nunca executados.

    E como C era para ser "próximo ao metal", faz sentido espelhar essa distinção também na sintaxe da linguagem.

  • A abordagem "função é apenas um valor", que forma a base da programação funcional, ganhou força nas linguagens comuns apenas recentemente, como evidenciado pela introdução tardia de lambdas em C ++, C # e Java (2011, 2007, 2014).

svick
fonte
12
C # tinha funções anônimas - que são apenas lambdas sem tipo de inferência e uma sintaxe desajeitado - desde 2005.
Eric Lippert
2
"De uma perspectiva mais técnica, o código (que é composto de funções) e os dados são separados" - algumas linguagens, mais sabidamente os LISPs não fazem essa separação e realmente não tratam códigos e dados de maneira muito diferente. (Lisps são o exemplo mais conhecido, mas há um monte de outras linguagens como REBOL que fazer isso)
Benjamin Gruenbaum
1
@BenjaminGruenbaum Eu estava falando sobre código compilado na memória, não sobre o nível do idioma.
svick
C possui indicadores de função que, pelo menos um pouco, podem ser considerados apenas mais um valor. Um valor perigoso para se mexer, com certeza, mas coisas mais estranhas aconteceram.
Patrick Hughes
@PatrickHughes Sim, eu os mencionei no meu segundo ponto. Mas os ponteiros de função são bem diferentes das funções.
svick
59

É porque é importante que os humanos reconheçam que funções não são apenas "outra entidade nomeada". Às vezes, faz sentido manipulá-los como tal, mas eles ainda podem ser reconhecidos rapidamente.

Realmente não importa o que o computador pense sobre a sintaxe, pois uma bolha incompreensível de caracteres é boa para uma máquina interpretar, mas isso seria quase impossível para os humanos entenderem e manterem.

É realmente a mesma razão pela qual temos tempo e para loops, switch e se mais, etc, mesmo que todos eles acabem se resumindo a uma instrução de comparação e salto. O motivo é que existe para o benefício dos humanos em manter e entender o código.

Ter suas funções como "outra entidade nomeada" da maneira que você está propondo tornará seu código mais difícil de ver e, portanto, mais difícil de entender.

whatsisname
fonte
12
Discordo que tratar funções como entidades nomeadas necessariamente torna o código mais difícil de entender. Isso quase certamente é verdade para qualquer código que segue um paradigma processual, mas pode não ser verdade para o código que segue um paradigma funcional.
Kyle Strand
29
"É realmente a mesma razão pela qual temos tempo e para loops, switch e se mais, etc., mesmo que todos eles acabem se resumindo a uma instrução de comparação e salto. " +1 a isso. Se todos os programadores estivessem à vontade com a linguagem de máquina, não precisaríamos de todas essas linguagens de programação sofisticadas (nível alto ou baixo). Mas a verdade é: todo mundo tem um nível de conforto diferente de quão perto da máquina deseja escrever seu código. Depois de encontrar seu nível, basta seguir a sintaxe fornecida (ou escrever suas próprias especificações de linguagem e compilador, se você estiver realmente preocupado).
Hoki
12
+1. Uma versão mais concisa pode ser "Por que todas as línguas naturais distinguem substantivos dos verbos?"
msw
2
"uma bolha incompreensível de caracteres é boa para uma máquina interpretar, mas isso seria quase impossível para os humanos entenderem e manterem" Que qualificação precipitada para uma mudança sintática tão modesta, como proposto na pergunta. Um se adapta rapidamente à sintaxe. Essa proposta é um afastamento muito menos radical da convenção do que o método OO chamado sintaxe object.method (args) estava em seu tempo, mas este último não provou ser quase impossível para os seres humanos entenderem e manterem. Apesar do fato de que na maioria das linguagens OO, os métodos não devem ser considerados armazenados em instâncias de classe.
Marc van Leeuwen 27/09
4
@MarcvanLeeuwen. Seu comentário é verdadeiro e faz sentido, mas alguma confusão é provocada pela maneira como a postagem original é editada. Na verdade, existem duas perguntas: (i) Por que é assim? e (ii) Por que não dessa maneira? . A resposta whatsisnamefoi abordar mais o primeiro ponto (e alertar sobre algum perigo de remover essas falhas), enquanto o seu comentário está mais relacionado à segunda parte da pergunta. É possível, de fato, alterar essa sintaxe (e, como você descreveu, isso já foi feito muitas vezes ...), mas não serve para todos (já que oop também não serve para todos.
30714 Hoki
10

Você pode estar interessado em aprender que, em tempos pré-históricos, uma linguagem chamada ALGOL 68 usava uma sintaxe próxima à proposta. Reconhecendo que os identificadores de função estão vinculados a valores, assim como outros identificadores, você pode, nesse idioma, declarar uma função (constante) usando a sintaxe

nome do tipo de função = ( lista de parâmetros ) tipo de resultado : corpo ;

Concretamente, seu exemplo seria

PROC (INT)INT add one = (INT n) INT: n+1;

Reconhecendo a redundância em que o tipo inicial pode ser lido no RHS da declaração e, sendo um tipo de função sempre iniciado PROC, isso pode (e geralmente seria) ser contratado para

PROC add one = (INT n) INT: n+1;

mas observe que o =item ainda vem antes da lista de parâmetros. Observe também que, se você quiser uma variável de função (à qual outro valor do mesmo tipo de função possa ser atribuído posteriormente), ele =deverá ser substituído por :=, fornecendo um dos

PROC (INT)INT func var := (INT n) INT: n+1;
PROC func var := (INT n) INT: n+1;

No entanto, neste caso, ambas as formas são de fato abreviações; como o identificador func vardesigna uma referência a uma função gerada localmente, o formulário totalmente expandido seria

REF PROC (INT)INT func var = LOC PROC (INT)INT := (INT n) INT: n+1;

É fácil se acostumar com essa forma sintática específica, mas claramente não tinha muitos seguidores em outras linguagens de programação. Mesmo linguagens de programação funcionais como Haskell preferem o estilo f n = n+1com = a seguir a lista de parâmetros. Eu acho que o motivo é principalmente psicológico; afinal, mesmo os matemáticos nem sempre preferem, como eu, f = nn + 1 sobre f ( n ) = n + 1.

A propósito, a discussão acima destaca uma diferença importante entre variáveis ​​e funções: as definições de funções geralmente vinculam um nome a um valor específico da função, que não pode ser alterado posteriormente, enquanto as definições de variáveis ​​geralmente introduzem um identificador com um valor inicial , mas que pode mudar mais tarde. (Não é uma regra absoluta; variáveis ​​de função e constantes não funcionais ocorrem na maioria dos idiomas.) Além disso, em idiomas compilados, o valor vinculado em uma definição de função geralmente é uma constante em tempo de compilação, para que as chamadas para a função possam ser compilado usando um endereço fixo no código. Em C / C ++, isso é mesmo um requisito; o equivalente do ALGOL 68

PROC (REAL) REAL f = IF mood=sunny THEN sin ELSE cos FI;

não pode ser escrito em C ++ sem introduzir um ponteiro de função. Esse tipo de limitação específica justifica o uso de uma sintaxe diferente para definições de função. Mas eles dependem da semântica da linguagem e a justificativa não se aplica a todas as línguas.

Marc van Leeuwen
fonte
1
"Os matemáticos não preferem f = nn + 1 sobre f ( n ) = n + 1" ... Sem mencionar os físicos, que gostam de escrever apenas f = n + 1 ...
leftaroundabout
1
@leftaroundabout é porque ⟼ é uma dor de escrever. Honestamente.
Pierre Arlaud
8

Você mencionou Java e Scala como exemplos. No entanto, você ignorou um fato importante: essas não são funções, são métodos. Métodos e funções são fundamentalmente diferentes. Funções são objetos, métodos pertencem a objetos.

No Scala, que possui funções e métodos, existem as seguintes diferenças entre métodos e funções:

  • métodos podem ser genéricos, funções não
  • métodos podem não ter, uma ou muitas listas de parâmetros, as funções sempre têm exatamente uma lista de parâmetros
  • métodos podem ter uma lista de parâmetros implícita, funções não podem
  • métodos podem ter parâmetros opcionais com argumentos padrão, funções não podem
  • métodos podem ter parâmetros repetidos, funções não
  • métodos podem ter parâmetros de nome, funções não podem
  • métodos podem ser chamados com argumentos nomeados, funções não podem
  • funções são objetos, métodos não são

Portanto, sua substituição proposta simplesmente não funciona, pelo menos nesses casos.

Jörg W Mittag
fonte
2
"Funções são objetos, métodos pertencem a objetos." Isso se aplica a todos os idiomas (como C ++)?
svick
9
"métodos podem ter parâmetros de nome, funções não" - essa não é uma diferença fundamental entre métodos e funções, é apenas uma peculiaridade do Scala. O mesmo acontece com a maioria (todos?) Dos outros.
user253751
1
Os métodos são fundamentalmente apenas um tipo especial de funções. -1. Observe que Java (e por extensão Scala) não possui nenhum outro tipo de função. Suas "funções" são objetos com um método (em geral, funções podem não ser objetos ou mesmo valores de primeira classe; se são depende do idioma).
Jan Hudec
@JanHudec: Semântica, Java possui funções e métodos; usa a terminologia "métodos estáticos" ao se referir a funções, mas essa terminologia não apaga a distinção semântica.
Supercat
3

As razões pelas quais consigo pensar são:

  • É mais fácil para o compilador saber o que estamos declarando.
  • É importante sabermos (de uma maneira trivial) se isso é uma função ou uma variável. As funções geralmente são caixas pretas e não nos importamos com sua implementação interna. Não gosto de inferência de tipo em tipos de retorno no Scala, porque acredito que é mais fácil usar uma função que tem um tipo de retorno: geralmente é a única documentação fornecida.
  • E a mais importante é a seguinte, a estratégia de multidão usada no design de linguagens de programação. O C ++ foi criado para roubar programadores de C, e o Java foi projetado de uma maneira que não assusta os programadores de C ++, e o C # para atrair programadores de Java. Até o C #, que eu acho que é uma linguagem muito moderna, com uma equipe incrível por trás, copiou alguns erros do Java ou até do C.
Sleiman Jneidi
fonte
2
"... e C # para atrair programadores Java" - isso é questionável, o C # é muito mais semelhante ao C ++ do que o Java. e às vezes parece que ele foi feito intencionalmente incompatível com Java (sem curingas, há classes internas, sem retorno Tipo covariância ...)
Sarge Borsch
1
@ SargeBorsch Eu não acho que foi intencionalmente incompatível com Java, tenho certeza de que a equipe de C # simplesmente tentou fazer o que é certo ou melhor, do jeito que você quiser. A Microsoft já escreveu seu próprio Java e JVM e foi processada. Portanto, a equipe de C # provavelmente estava muito motivada para eclipsar o Java. É certamente incompatível, e melhor para isso. O Java começou com algumas limitações básicas e fico feliz que a equipe do C # tenha escolhido, por exemplo, fazer genéricos de maneira diferente (visível no sistema de tipos e não apenas no açúcar).
Codenheim
2

Mudando a questão, se alguém não está interessado em tentar editar o código-fonte em uma máquina com muita restrição de RAM ou minimizar o tempo para lê-lo em um disquete, o que há de errado em usar palavras-chave?

Certamente é melhor ler do x=y+zque store the value of y plus z into x, mas isso não significa que os caracteres de pontuação sejam inerentemente "melhores" que as palavras-chave. Se as variáveis i, je ksão Integer, e xé Real, considere as seguintes linhas em Pascal:

k := i div j;
x := i/j;

A primeira linha executará uma divisão de número inteiro truncada, enquanto a segunda executará uma divisão de número real. A distinção pode ser feita muito bem porque Pascal usa divcomo seu operador de divisão de número inteiro truncado, em vez de tentar usar um sinal de pontuação que já tem outro objetivo (divisão em número real).

Embora existam alguns contextos nos quais pode ser útil tornar concisa a definição de uma função (por exemplo, um lambda que é usado como parte de outra expressão), geralmente as funções se destacam e são facilmente reconhecíveis visualmente como funções. Embora seja possível tornar a distinção muito mais sutil e usar apenas caracteres de pontuação, qual seria o objetivo? Dizer Function Foo(A,B: Integer; C: Real): Stringdeixa claro qual é o nome da função, quais parâmetros ela espera e o que ela retorna. Talvez alguém possa encurtá-lo em seis ou sete caracteres substituindo-o Functionpor alguns caracteres de pontuação, mas o que seria ganho?

Outro aspecto a ser observado é que, na maioria das estruturas, existe uma diferença fundamental entre uma declaração que sempre associa um nome a um método específico ou a uma ligação virtual específica, e que cria uma variável que identifica inicialmente um método ou ligação específica, mas pode ser alterado em tempo de execução para identificar outro. Como esses conceitos são semanticamente muito diferentes na maioria das estruturas procedurais, faz sentido que eles tenham sintaxe diferente.

supercat
fonte
3
Eu não acho que essa pergunta seja sobre concisão. Especialmente porque, por exemplo, void f() {}é realmente mais curto que o equivalente lambda em C ++ ( auto f = [](){};), C # ( Action f = () => {};) e Java ( Runnable f = () -> {};). A concisão das lambdas vem da inferência e omissão de tipos return, mas não acho que isso esteja relacionado ao que essas perguntas fazem.
svick
2

Bem, o motivo pode ser que esses idiomas não sejam funcionais o suficiente, por assim dizer. Em outras palavras, você raramente define funções. Portanto, o uso de uma palavra-chave extra é aceitável.

Nos idiomas da herança ML ou Miranda, OTOH, você define funções na maioria das vezes. Veja um código Haskell, por exemplo. É literalmente principalmente uma sequência de definições de funções, muitas delas possuem funções locais e funções locais dessas funções locais. Portanto, uma palavra-chave divertida em Haskell seria um erro tão grande quanto exigir uma declaração de afirmação em uma linguagem imperativa para começar com a atribuição . A atribuição de causas é provavelmente de longe a declaração mais frequente.

Ingo
fonte
1

Pessoalmente, não vejo falha fatal em sua ideia; você pode achar que é mais complicado do que o esperado expressar algumas coisas usando sua nova sintaxe e / ou pode precisar revê-la (adicionando vários casos especiais e outros recursos, etc.), mas duvido que você se encontre precisando abandonar completamente a ideia.

A sintaxe que você propôs parece mais ou menos uma variante de alguns dos estilos de notação às vezes usados ​​para expressar funções ou tipos de funções em matemática. Isso significa que, como todas as gramáticas, provavelmente atrairá mais alguns programadores do que outros. (Como matemático, eu gosto disso.)

No entanto, você deve observar que, na maioria dos idiomas, a defsintaxe -style (ou seja, a sintaxe tradicional) se comporta de maneira diferente de uma atribuição de variável padrão.

  • Na família Ce C++, as funções geralmente não são tratadas como "objetos", ou seja, pedaços de dados digitados a serem copiados e colocados na pilha e outros enfeites. (Sim, você pode ter ponteiros de função, mas eles ainda apontam para código executável, não para "dados" no sentido típico.)
  • Na maioria das linguagens OO, há tratamento especial para métodos (ou seja, funções-membro); isto é, não são apenas funções declaradas dentro do escopo de uma definição de classe. A diferença mais importante é que o objeto no qual o método está sendo chamado geralmente é passado como um primeiro parâmetro implícito para o método. O Python torna isso explícito com self(que, a propósito, não é realmente uma palavra-chave; você pode tornar qualquer identificador válido o primeiro argumento de um método).

Você precisa considerar se sua nova sintaxe precisa (e esperamos intuitivamente) representar o que o compilador ou intérprete está realmente fazendo. Pode ajudar a ler, digamos, a diferença entre lambdas e métodos no Ruby; isso lhe dará uma idéia de como seu paradigma de funções são apenas dados difere do paradigma OO / procedimento típico.

Kyle Strand
fonte
1

Para alguns idiomas, funções não são valores. Em tal linguagem para dizer que

val f = << i : int  ... >> ;

é uma definição de função, enquanto

val a = 1 ;

declara uma constante, é confuso porque você está usando uma sintaxe para significar duas coisas.

Outros idiomas, como ML, Haskell e Scheme, tratam funções como valores de primeira classe, mas fornecem ao usuário uma sintaxe especial para declarar constantes com valor de função. * Eles estão aplicando a regra de que "o uso reduz a forma". Ou seja, se uma construção é comum e detalhada, você deve fornecer uma abreviação ao usuário. É deselegante fornecer ao usuário duas sintaxes diferentes que significam exatamente a mesma coisa; às vezes a elegância deve ser sacrificada à utilidade.

Se, em seu idioma, as funções são de 1ª classe, por que não tentar encontrar uma sintaxe concisa o suficiente para que você não fique tentado a encontrar um açúcar sintático?

- Editar -

Outra questão que ninguém levantou (ainda) é a recursão. Se você permitir

{ 
    val f = << i : int ... g(i-1) ... >> ;
    val g = << j : int ... f(i-1) ... >> ;
    f(x)
}

e você permite

{
    val a = 42 ;
    val b = a + 1 ;
    a
} ,

segue-se que você deve permitir

{
    val a = b + 1 ; 
    val b = a - 1 ;
    a
} ?

Em um idioma preguiçoso (como Haskell), não há problema aqui. Em um idioma com praticamente nenhuma verificação estática (como LISP), não há problema aqui. Mas em uma linguagem ansiosa verificada estaticamente, você deve ter cuidado com a definição das regras de verificação estática, se desejar permitir as duas primeiras e proibir a última.

- Fim da edição -

* Pode-se argumentar que Haskell não pertence a esta lista. Ele fornece duas maneiras de declarar uma função, mas ambas são, em certo sentido, generalizações da sintaxe para declarar constantes de outros tipos

Theodore Norvell
fonte
0

Isso pode ser útil em linguagens dinâmicas em que o tipo não é tão importante, mas não é legível em linguagens estáticas de tipo, onde você sempre deseja saber o tipo de sua variável. Além disso, nas linguagens orientadas a objetos, é muito importante conhecer o tipo de sua variável, para saber quais operações ela suporta.

No seu caso, uma função com 4 variáveis ​​seria:

(int, long, double, String => int) addOne = (x, y, z, s) => {
  return x + 1;
}

Quando olho para o cabeçalho da função e vejo (x, y, z, s), mas não conheço os tipos dessas variáveis. Se eu quiser saber o tipo de zqual é o terceiro parâmetro, terei que examinar o início da função e começar a contar 1, 2, 3 e depois ver que o tipo é double. No primeiro modo, olho diretamente e vejo double z.

m3th0dman
fonte
3
É claro que existe uma coisa maravilhosa chamada inferência de tipo, que permite escrever algo como var addOne = (int x, long y, double z, String s) => { x + 1 }uma linguagem estaticamente não-imbecil de sua escolha (exemplos: C #, C ++, Scala). Mesmo a inferência de tipo local muito limitada usada pelo C # é completamente suficiente para isso. Portanto, esta resposta está apenas criticando uma sintaxe específica duvidosa em primeiro lugar, e que na verdade não é usada em nenhum lugar (embora a sintaxe de Haskell tenha um problema muito semelhante).
amon
4
@amon Sua resposta pode estar criticando a sintaxe, mas também aponta que a sintaxe proposta na pergunta pode não ser "natural" para todos.
1
@amon A utilidade da inferência de tipo não é uma coisa maravilhosa para todos. Se você lê código com mais frequência do que escreve, então a inferência de tipo é ruim porque você deve inferir na sua cabeça o tipo ao ler o código; e é muito mais rápido ler o tipo do que realmente pensar sobre o tipo usado.
M3th0dman 28/09/14
1
As críticas me parecem válidas. Para Java, o OP parece pensar que [entrada, saída, nome, entrada] é uma definição de função mais simples / clara do que simplesmente [saída, nome, entrada]? Como o @ m3th0dman afirma, com assinaturas mais longas, a abordagem 'limpa' do OP se torna muito demorada.
Michael
0

Há uma razão muito simples para se fazer essa distinção na maioria dos idiomas: é necessário distinguir avaliação e declaração . Seu exemplo é bom: por que não gostar de variáveis? Bem, expressões de variáveis ​​são avaliadas imediatamente.

Haskell tem um modelo especial em que não há distinção entre avaliação e declaração, razão pela qual não há necessidade de uma palavra-chave especial.

Florian Margaine
fonte
2
Mas alguma sintaxe para funções lambda também resolve isso, então por que não usar isso?
svick
0

As funções são declaradas de maneira diferente de literais, objetos etc. na maioria dos idiomas porque são usadas de maneira diferente, depuradas de maneira diferente e apresentam diferentes fontes potenciais de erro.

Se uma referência de objeto dinâmico ou um objeto mutável for passado para uma função, a função poderá alterar o valor do objeto enquanto ele é executado. Esse tipo de efeito colateral pode dificultar o acompanhamento de uma função se estiver aninhada em uma expressão complexa, e esse é um problema comum em linguagens como C ++ e Java.

Considere a depuração de algum tipo de módulo do kernel em Java, onde cada objeto possui uma operação toString (). Embora seja esperado que o método toString () restaure o objeto, pode ser necessário desmontar e remontar o objeto para converter seu valor em um objeto String. Se você estiver tentando depurar os métodos que toString () chamará (em um cenário de gancho e modelo) para fazer seu trabalho e destacar acidentalmente o objeto na janela de variáveis ​​da maioria dos IDEs, ele poderá travar o depurador. Isso ocorre porque o IDE tentará toString () o objeto que chama o próprio código que você está no processo de depuração. Nenhum valor primitivo é um lixo assim, porque o significado semântico dos valores primitivos é definido pela linguagem, não pelo programador.

Trixie Wolf
fonte