Melhor explicação de quando usar Importações / Dependências

O manual ” Writing R Extensions ” fornece as seguintes orientações sobre quando usar Imports ou Depends:

As regras gerais são

  • Pacotes cujo namespace é necessário apenas para carregar o pacote usando a biblioteca (pkgname) devem estar listados no campo ‘Importações’ e não no campo ‘Dependências’.
  • Os pacotes que precisam ser anexados para carregar o pacote com sucesso usando a biblioteca (pkgname) devem estar listados apenas no campo ‘Dependências’.

Alguém pode fornecer um pouco mais de clareza sobre isso? Como sei quando meu pacote precisa apenas de namespaces carregados versus quando eu preciso de um pacote a ser anexado? Quais são os exemplos de ambos? Eu acho que o pacote típico é apenas uma coleção de funções que às vezes chamam funções em outros pacotes (onde um pouco de trabalho já foi codificado). Este cenário é 1 ou 2 acima?

Editar

Eu escrevi uma postagem de blog com uma seção sobre esse tópico específico (pesquise por ‘Imports v Depends’). O visual torna muito mais fácil de entender.

"Imports" é mais seguro que "Depends" (e também faz com que um pacote o use como “melhor cidadão” em relação a outros pacotes que usam "Depends" ).

Uma diretiva "Depends" tenta garantir que uma function de outro pacote esteja disponível, anexando o outro pacote ao caminho de pesquisa principal (ou seja, a lista de ambientes retornados por search() ). Essa estratégia pode, no entanto, ser frustrada se outro pacote, carregado posteriormente, colocar uma function identicamente identificada anteriormente no caminho de pesquisa. Chambers ( no SoDA ) usa o exemplo da function "gam" , que é encontrada nos pacotes gam e mgcv . Se dois outros pacotes foram carregados, um deles dependendo do gam e um dependendo do mgcv , a function encontrada por chamadas ao gam() dependeria da ordem em que esses dois pacotes foram anexados. Não é bom.

Uma diretiva "Imports" coloca o pacote importado em (pesquisado imediatamente após ), em vez de no caminho de pesquisa regular. Se qualquer um dos pacotes no exemplo acima usasse o mecanismo "Imports" , os problemas seriam melhorados de duas maneiras. (1) O pacote poderia ganhar controle sobre qual function mgcv é usada. (2) Mantendo o caminho de busca principal livre dos objects importados, ele não iria potencialmente quebrar a dependência do outro pacote na outra function mgcv .

É por isso que usar namespaces é uma boa prática, por que agora é reforçada pelo CRAN e (em particular) por que usar "Imports" é mais seguro do que usar "Depends" .


Editado para adicionar uma advertência importante:

Infelizmente, há uma exceção comum aos conselhos acima: se o seu pacote depende de um pacote A que "Depends" de outro pacote B , seu pacote provavelmente precisará append A com uma "Depends Diretriz de "Depends .

Isso ocorre porque as funções no pacote A foram escritas com a expectativa de que o pacote B e suas funções seriam anexadas ao caminho search() .

Uma diretiva "Depends" carregará e appendá o pacote A , no qual a diretiva "Depends" próprio pacote A , em uma reação em cadeia, fará com que o pacote B seja carregado e anexado também. As funções no pacote A poderão, então, encontrar as funções no pacote B em que elas dependem.

Uma diretiva "Imports" será carregada, mas não appendá o pacote A e não carregará nem appendá o pacote B ( "Imports" , afinal, espera que os escritores de pacotes usem o mecanismo de namespace, e que o pacote A esteja usando "Imports" para apontar para qualquer function em B que precise acessar.) Chama por suas funções para qualquer function em O pacote A que depende de funções no pacote B irá falhar.

As duas únicas soluções são:

  1. Ter seu pacote append o pacote A usando uma diretiva "Depends" .
  2. Melhor a longo prazo, entre em contato com o mantenedor do pacote A e peça-lhes para fazer um trabalho mais cuidadoso na construção de seu espaço de nome (nas palavras de Martin Morgan nesta resposta relacionada ).

Hadley Wickham dá uma explicação fácil ( http://r-pkgs.had.co.nz/namespace.html ):

Listar um pacote em Depends ou Imports garante que ele seja instalado quando necessário. A principal diferença é que, quando Imports apenas carrega o pacote, Depends anexa. Não há outras diferenças. […]

A menos que haja uma boa razão para o contrário, você deve sempre listar os pacotes em Imports não em Depends . Isso porque um bom pacote é autocontido e minimiza as alterações no ambiente global (incluindo o caminho de pesquisa). A única exceção é se o pacote for projetado para ser usado em conjunto com outro pacote. Por exemplo, o pacote analógico baseia-se no vegan. Não é útil sem vegan, por isso tem vegan em Depends em vez de Imports . Da mesma forma, ggplot2 deve realmente depender de escalas, em vez de importá-lo.

Chambers no SfDA diz para usar ‘Importações’ quando este pacote usa um mecanismo ‘namespace’ e já que todos os pacotes são agora obrigados a tê-los, então a resposta agora pode ser sempre usar ‘Importações’. No passado, os pacotes poderiam ter sido carregados sem ter namespaces e, nesse caso, você precisaria usar Depends.

Aqui está uma pergunta simples para ajudá-lo a decidir qual usar:

Seu pacote exige que o usuário final tenha access direto às funções de outro pacote?

  • NÃO -> Importações (resposta mais comum)
  • SIM -> Depende

A única vez que você deve usar ‘Depende’ é quando o seu pacote é um complemento ou um complemento para outro pacote, onde o usuário final estará usando funções do seu pacote e do pacote ‘Dependos’ em seu código. Se o seu usuário final estiver apenas interagindo com suas funções, e o outro pacote estará apenas trabalhando nos bastidores, use ‘Importações’.

A ressalva para isso é que se você adicionar um pacote a ‘Importações’, como você normalmente deveria, seu código precisará referir-se a funções daquele pacote, usando a syntax do namespace completo, por exemplo dplyr::mutate() , ao invés de apenas mutate() . Isso torna o código um pouco mais complicado de ler, mas é um pequeno preço a pagar por uma melhor higiene do pacote.