Estou interessado em qual é a maneira "correta" de escrever funções com argumentos opcionais em R. Com o tempo, deparei-me com alguns trechos de código que seguem uma rota diferente aqui e não consegui encontrar uma posição (oficial) adequada neste tópico.
Até agora, escrevi argumentos opcionais como este:
fooBar <- function(x,y=NULL){
if(!is.null(y)) x <- x+y
return(x)
}
fooBar(3) # 3
fooBar(3,1.5) # 4.5
A função simplesmente retorna seu argumento se apenas x
for fornecida. Ele usa um NULL
valor padrão para o segundo argumento e, se esse argumento não for NULL
, a função adicionará os dois números.
Como alternativa, pode-se escrever a função dessa maneira (onde o segundo argumento precisa ser especificado pelo nome, mas também pode-se unlist(z)
ou definir z <- sum(...)
):
fooBar <- function(x,...){
z <- list(...)
if(!is.null(z$y)) x <- x+z$y
return(x)
}
fooBar(3) # 3
fooBar(3,y=1.5) # 4.5
Pessoalmente, prefiro a primeira versão. No entanto, posso ver o bem e o mal com ambos. A primeira versão é um pouco menos propensa a erros, mas a segunda poderia ser usada para incorporar um número arbitrário de opcionais.
Existe uma maneira "correta" de especificar argumentos opcionais no R? Até agora, decidi pela primeira abordagem, mas ambas podem ocasionalmente parecer um pouco "hacky".
xy.coords
ver uma abordagem comumente usada.xy.coords
mencionado por Carl Witthoft l pode ser encontrado em xy.coordsRespostas:
Você também pode usar
missing()
para testar se o argumentoy
foi ou não fornecido:fonte
missing()
também é mais expressivo no sentido em que "diz o que significa". Além disso, permite que os usuários passem um valor NULL, em locais onde isso faz sentido!@param x numeric; something something; @param y numeric; **optional** something something; @param z logical; **optional** something something
missing()
é terrível quando você deseja passar argumentos de uma função para outra.Para ser sincero, gosto da primeira maneira do OP de realmente começar com um
NULL
valor e depois checá-lois.null
(principalmente porque é muito simples e fácil de entender). Talvez dependa da maneira como as pessoas estão acostumadas a codificar, mas o Hadley parece também apoiar ois.null
caminho:Do livro de Hadley "Advanced-R", capítulo 6, Funções, pág. 84 (para a versão online, verifique aqui ):
fonte
NULL
caminho há um bom tempo e, provavelmente, é por isso que estou mais acostumado quando vejo códigos-fonte. Parece mais natural para mim. Dito isto, como você diz que a base R adota as duas abordagens, realmente se resume às preferências individuais.is.null
emissing
dependendo do contexto e para que o argumento é usado.Estas são minhas regras práticas:
Se os valores padrão puderem ser calculados a partir de outros parâmetros, use expressões padrão como em:
se não estiver usando falta
No caso raro de você achar que um usuário pode especificar um valor padrão que dure uma sessão R inteira, use
getOption
Se alguns parâmetros se aplicarem, dependendo da classe do primeiro argumento, use um S3 genérico:
Use
...
somente quando estiver passando parâmetros adicionais para outra funçãoPor fim, se você escolher o uso
...
sem passar os pontos para outra função, avise o usuário que sua função está ignorando quaisquer parâmetros não utilizados, pois pode ser muito confuso caso contrário:fonte
NULL
na assinatura da função, pois é mais conveniente para criar funções que se encaixam perfeitamente.Existem várias opções e nenhuma delas é a maneira correta oficial e nenhuma delas está realmente incorreta, embora possam transmitir informações diferentes para o computador e para outras pessoas que estão lendo seu código.
Para o exemplo dado, acho que a opção mais clara seria fornecer um valor padrão de identidade, neste caso, faça algo como:
Essa é a menor das opções mostradas até agora, e a falta pode ajudar na legibilidade (e às vezes até na velocidade da execução). É claro que o que está sendo retornado é a soma de xey, e você pode ver que y não recebe um valor que será 0 que, quando adicionado a x, resultará apenas em x. Obviamente, se algo mais complicado que a adição for usado, será necessário um valor de identidade diferente (se houver).
Uma coisa que eu realmente gosto nessa abordagem é que fica claro qual é o valor padrão ao usar a
args
função ou até mesmo olhar para o arquivo de ajuda (você não precisa rolar para baixo para os detalhes, está ali no uso )A desvantagem desse método é que quando o valor padrão é complexo (exigindo várias linhas de código), provavelmente reduziria a legibilidade para tentar colocar tudo isso no valor padrão e as abordagens
missing
ouNULL
se tornam muito mais razoáveis.Algumas das outras diferenças entre os métodos aparecerão quando o parâmetro estiver sendo transmitido para outra função ou ao usar as funções
match.call
ousys.call
.Portanto, acho que o método "correto" depende do que você planeja fazer com esse argumento específico e das informações que deseja transmitir aos leitores do seu código.
fonte
Eu tenderia a preferir usar NULL para ter clareza do que é necessário e do que é opcional. Uma palavra de aviso sobre o uso de valores padrão que dependem de outros argumentos, conforme sugerido por Jthorpe. O valor não é definido quando a função é chamada, mas quando o argumento é referenciado pela primeira vez! Por exemplo:
Por outro lado, se você referenciar y antes de alterar x:
Isso é um pouco perigoso, porque torna difícil acompanhar o que "y" está sendo inicializado como se não fosse chamado no início da função.
fonte
Só queria ressaltar que a
sink
função interna tem bons exemplos de diferentes maneiras de definir argumentos em uma função:fonte
que tal agora?
Então tente:
fonte