Quais são as diferenças entre os operadores de atribuição =
e <-
em R?
Como mostra seu exemplo, =
e <-
tem precedência de operador ligeiramente diferente (que determina a ordem da avaliação quando eles são misturados na mesma expressão). De fato, ?Syntax
em R fornece a seguinte tabela de precedência do operador, da mais alta para a mais baixa:
…
‘-> ->>’ rightwards assignment
‘<- <<-’ assignment (right to left)
‘=’ assignment (right to left)
…
Mas essa é a única diferença?
Desde que você estava perguntando sobre os operadores de atribuição : sim, essa é a única diferença. No entanto, você seria perdoado por acreditar no contrário. Até a documentação R ?assignOps
afirma que existem mais diferenças:
O operador <-
pode ser usado em qualquer lugar, enquanto o operador =
é permitido apenas no nível superior (por exemplo, na expressão completa digitada no prompt de comando) ou como uma das subexpressões em uma lista entre expressões.
Não vamos enfatizar muito bem: a documentação do R está (sutilmente) errada [ 1 ] . Isso é fácil de mostrar: precisamos apenas encontrar um contra-exemplo do =
operador que não esteja (a) no nível superior nem (b) uma subexpressão em uma lista de expressões (ie {…; …}
). - Sem mais delongas:
x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
Claramente, realizamos uma atribuição, usando =
, fora dos contextos (a) e (b). Então, por que a documentação de um recurso central da linguagem R está errada há décadas?
É porque na sintaxe de R o símbolo =
tem dois significados distintos que são rotineiramente confundidos:
- O primeiro significado é como um operador de atribuição . É disso que falamos até agora.
- O segundo significado não é um operador, mas um token de sintaxe que sinaliza o argumento chamado passando em uma chamada de função. Ao contrário do
=
operador, ele não executa nenhuma ação no tempo de execução, apenas altera a maneira como uma expressão é analisada.
Vamos ver.
Em qualquer parte do código da forma geral…
‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)
... o =
é o sinal que define chamado argumento passando: ele é não o operador de atribuição. Além disso, =
é totalmente proibido em alguns contextos sintáticos:
if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …
Qualquer uma dessas opções gerará um erro “inesperado '=' em ‹bla›”.
Em qualquer outro contexto, =
refere-se à chamada do operador de atribuição. Em particular, apenas colocar parênteses em torno da subexpressão torna qualquer uma das alternativas (a) acima e (b) uma atribuição . Por exemplo, o seguinte executa a atribuição:
median((x = 1 : 10))
Mas também:
if (! (nf = length(from))) return()
Agora você pode objetar que esse código é atroz (e você pode estar certo). Mas peguei esse código da base::file.copy
função (substituindo <-
por =
) - é um padrão generalizado em grande parte da base de código R principal.
A explicação original de John Chambers , na qual a documentação do R provavelmente está baseada, na verdade explica isso corretamente:
[a =
atribuição é] permitida em apenas dois lugares da gramática: no nível superior (como um programa completo ou expressão digitada pelo usuário); e quando isolado da estrutura lógica circundante, por chaves ou um par extra de parênteses.
Uma confissão: eu menti antes. Não é uma diferença adicional entre a =
e <-
operadores: eles chamam funções distintas. Por padrão, essas funções fazem a mesma coisa, mas você pode substituí-las separadamente para alterar o comportamento. Por outro lado, <-
e ->
(atribuição da esquerda para a direita), embora sintaticamente distintos, sempre chamam a mesma função. Substituir um também substitui o outro. Saber isso raramente é prático, mas pode ser usado para algumas travessuras divertidas .
<-
símbolo vêm de teclados antigos da APL, que na verdade tinham uma única<-
tecla.