From emil@bode @ending from d@n@@kn@w@nl  Mon Oct  8 15:38:18 2018
From: emil@bode @ending from d@n@@kn@w@nl (Emil Bode)
Date: Mon, 8 Oct 2018 13:38:18 +0000
Subject: [Rd] Warning when calling formals() for `[`.
In-Reply-To: <02b801c9-4e41-4e29-1d3d-c575da0f6405@sapo.pt>
References: <CA+JCgN254QaHVepo03ZuGLsatwmjfDSnUP3yq43N6TguBdWN5g@mail.gmail.com>
 <634D4A0E-A036-4FEB-8C85-978262B46EA7@gmail.com>
 <550606ea-720a-ca30-a762-d8aaf2484661@sapo.pt>
 <B465FE70-797D-48E0-891E-41E3C6AF0C83@gmail.com>
 <02b801c9-4e41-4e29-1d3d-c575da0f6405@sapo.pt>
Message-ID: <B1C4B85E-7C01-42D9-BE12-1571A3E133CA@dans.knaw.nl>

Hello,

I agree the documentation of args can be improved, but the main question is what the return should be.
I guess the reason args() returns NULL is because of the way argument-matching works for primitives: there is a lot going on under the hood, and what arguments are/are not acceptable for `[` can't be stated as straightforward as we can with other functions.
Note also the difference in printing "sum" and "[": sum first prints "function(..., na.rm=FALSE)", whereas `[` jumps straight to the body. And this is not an artefact of printing it, as makes overwriting it makes clear: 
`[` <- function(x, i, j, ..., drop=FALSE) .Primitive("[")
exhibited very strange behaviour, where you need to call it twice/nested: 1[2] returns a primitive function, to get it to do its job you need 1[2](df, 3, 4) instead of df[3,4].
So general advice would probably be to stay away from messing with arguments with primitives, as ?args already hints at: " mainly used interactively (...). For programming, consider using formals instead." 
Basically, primitives are optimized and down to the core, which probably means the concept of an argument-list may not be as clear as it is with "normal" functions.
So working with args() on primitives comes with some risks, which probably is the reason that formals() always return NULL in that case. 
What is your use case?
If you really need a return value, I think you could catch NULL-values, something like this:
args <- function(name) {
  if(is.character(name)) name <- get(name, parent.frame(), mode='function')
  if(!is.function(name)) return(NULL)
  ret <- base::args(name)
  if(is.null(ret) && is.primitive(name)) {
    ret <- function(...) NULL
    environment(ret) <- parent.frame()
  }
  return(ret)
}

Which would just return "function(...) NULL" for args("["), which is of the expected class, but does not give you any real information. Would that help you?
Otherwise, to get to know the arguments there is of course "?"
And note that if there is a dispatch, it's possible to get the argument-list of a specific method, e.g. args(`[.data.frame`) works as expected (as it is not a primitive) 


Best regards, 
Emil Bode

?On 07/10/2018, 16:34, "R-devel on behalf of Rui Barradas" <r-devel-bounces at r-project.org on behalf of ruipbarradas at sapo.pt> wrote:

    Hello,
    
    This is because args(`[`) returns NULL and class(NULL) is NULL.
    So the question would be why is the return value of args(`[`) NULL?
    
    Rui Barradas
    
    ?s 15:14 de 07/10/2018, Peter Dalgaard escreveu:
    > 
    > 
    >> On 7 Oct 2018, at 16:04 , Rui Barradas <ruipbarradas at sapo.pt> wrote:
    >>
    >> Hello,
    >>
    >> I don't see why you say that the documentation seems to be wrong:
    >>
    >>
    >> class(args(`+`))
    >> #[1] "function"
    >>
    >>
    >> args() on a primitive does return a closure. At least in this case it does.
    > 
    > But in this case it doesn't:
    > 
    >> is.primitive(get("["))
    > [1] TRUE
    >> class(args(get("[")))
    > [1] "NULL"
    > 
    > Or, for that matter:
    > 
    >> is.primitive(`[`)
    > [1] TRUE
    >> class(args(`[`))
    > [1] "NULL"
    > 
    > -pd
    > 
    >>
    >>
    >> Rui Barradas
    >>
    >> ?s 14:05 de 07/10/2018, Peter Dalgaard escreveu:
    >>> There is more "fun" afoot here, but I don't recall what the point may be:
    >>>> args(get("+"))
    >>> function (e1, e2)
    >>> NULL
    >>>> args(get("["))
    >>> NULL
    >>>> get("[")
    >>> .Primitive("[")
    >>>> get("+")
    >>> function (e1, e2)  .Primitive("+")
    >>> The other index operators, "[[", "[<-", "[[<-" are similar
    >>> The docs are pretty clear that args() on a primitive should yield a closure, so at least the documentation seems to be wrong.
    >>> -pd
    >>>> On 6 Oct 2018, at 19:26 , Laurent Gautier <lgautier at gmail.com> wrote:
    >>>>
    >>>> Hi,
    >>>>
    >>>> A short code example showing the warning might the only thing needed here:
    >>>>
    >>>> ```
    >>>>> formals(args(`[`))
    >>>> NULL
    >>>>
    >>>> *Warning message:In formals(fun) : argument is not a function*
    >>>>> is.function(`[`)
    >>>> [1] TRUE
    >>>>> is.primitive(`[`)
    >>>> [1] TRUE
    >>>> ```
    >>>>
    >>>> Now with an other primitive:
    >>>>
    >>>> ```
    >>>>> formals(args(`sum`))
    >>>> $...
    >>>>
    >>>>
    >>>> $na.rm
    >>>> [1] FALSE
    >>>>
    >>>>> is.function(`sum`)
    >>>> [1] TRUE
    >>>>> is.primitive(`sum`)
    >>>> [1] TRUE
    >>>>> class(`[`)
    >>>> [1] "function"
    >>>> ```
    >>>>
    >>>> Is this a feature ?
    >>>>
    >>>>
    >>>> Laurent
    >>>>
    >>>> 	[[alternative HTML version deleted]]
    >>>>
    >>>> ______________________________________________
    >>>> R-devel at r-project.org mailing list
    >>>> https://stat.ethz.ch/mailman/listinfo/r-devel
    >
    
    ______________________________________________
    R-devel at r-project.org mailing list
    https://stat.ethz.ch/mailman/listinfo/r-devel
    



[Rd] Warning when calling formals() for `[`.
Emil Bode