>>>>> Georgi Boshnakov 
>>>>>     on Mon, 1 Jul 2019 09:11:39 +0000 writes:

    > I run checks with R-devel rev. 76756 on several of my
    > packages which use S4, with no ill effects.  

Thank you, Georgi!

    > With the risk of not adding much, it seems that Martin's example, which
    > I repeat below, suggests a crossover between several
    > "signatures" involved here - the signature of the generic,
    > the signature of the method (the argument for setMethod()),
    > and the signature of the function object defining the method.

that's correct.

and the conformMethod() plus  rematchDefinition()  utility functions
have been created to deal with this problem "optimally" and consistently.

>>> r2 <- oligoFn(object=diag(2), target=array(42))
>>  Error in .local(object, target) :
>>      argument "target" is missing, with no default
>>> getMethod("oligoFn", signature(object="matrix", subset="missing", 
>>> target="array"))
>>
>> Method Definition:
>
>> function (object, subset, target, value)
>> {
>>   .local <- function (object, subset, target, value)
>>                   list(object = object, target = target)
>>   .local(object, target)
>> }


    > a) .local() seems superfluous here, since the signature of
    > the function object is identical to that of the generic.

that's only true in the *result*ing method,
but not in how the method was defined (the following code was in
my post) :

 setMethod("oligoFn", signature(object = "matrix", target="array"),   ## Method 
_ 2 _
     function(object, target) list(object=object, target=target))

Here, function object has arguments  (object, target)   only


    > b) "subset" is "missing" in the signature of the method
    > but it is (legally, I believe) present in the function
    > object. The call .local(object, target) would be
    > appropriate if "subset" was missing also from the
    > signature of the function object (the latter would be
    > illegal here). Alternatively, it could be named, as in
    > .local(object, target = target) or maybe even
    > .local(object, , target).

    > --
    > Georgi Boshnakov


The 2nd patch I committed -- the one mostly to
rematchDefiniton() --  does exactly that:  It uses .local()
calls where those argument *are* named which should be named.
==> hence the above example works fine there.

Martin

    > ------------------------------
> Date: Sat, 29 Jun 2019 22:44:49 +0200
> From: Martin Maechler <maech...@stat.math.ethz.ch>
> To: R-devel <r-devel@r-project.org>, Henrik Bengtsson
>         <henrik.bengts...@gmail.com>
> Cc: Martin Maechler <maech...@stat.math.ethz.ch>
> Subject: Re: [Rd] methods package: A _R_CHECK_LENGTH_1_LOGIC2_=true
>         error
> Message-ID: <23831.52673.201433.320...@stat.math.ethz.ch>
> Content-Type: text/plain; charset="utf-8"
> 
> >>>>> Martin Maechler
> >>>>>     on Sat, 29 Jun 2019 12:05:49 +0200 writes:
> 
> >>>>> Martin Maechler
> >>>>>     on Sat, 29 Jun 2019 10:33:10 +0200 writes:
> 
> >>>>> peter dalgaard
> >>>>>     on Fri, 28 Jun 2019 16:20:03 +0200 writes:
> 
 >>>> > On 28 Jun 2019, at 16:03 , Martin Maechler <maech...@stat.math.ethz.ch> 
 >>>> > wrote:
 >>>> >
 >>>> >>>>>> Henrik Bengtsson
 >>>> >>>>>>    on Thu, 27 Jun 2019 16:00:39 -0700 writes:
 >>>> >
 >>>> >> Using:
 >>>> >>
 >>>> >> untrace(methods::conformMethod)
 >>>> >> at <- c(12,4,3,2)
 >>>> >> str(body(methods::conformMethod)[[at]])
 >>>> >> ## language omittedSig <- omittedSig && (signature[omittedSig] != 
 >>>> >> "missing")
 >>>> >> cc <- 0L
 >>>> >> trace(methods::conformMethod, tracer = quote({
 >>>> >>  cc <<- cc + 1L
 >>>> >>  print(cc)
 >>>> >>  if (cc == 31) {  ## manually identified
 >>>> >>    untrace(methods::conformMethod)
 >>>> >>    trace(methods::conformMethod, at = list(at), tracer = quote({
 >>>> >>      str(list(signature = signature, mnames = mnames, fnames = fnames))
 >>>> >>      print(ls())
 >>>> >>      try(str(list(omittedSig = omittedSig, signature = signature)))
 >>>> >>    }))
 >>>> >>  }
 >>>> >> }))
 >>>> >> loadNamespace("oligo")
 >>>> >>
 >>>> >> gives:
 >>>> >>
 >>>> >> Untracing function "conformMethod" in package "methods"
 >>>> >> Tracing function "conformMethod" in package "methods"
 >>>> >> Tracing conformMethod(signature, mnames, fnames, f, fdef, definition)
 >>>> >> step 12,4,3,2
 >>>> >> List of 3
 >>>> >> $ signature: Named chr [1:4] "TilingFeatureSet" "ANY" "ANY" "array"
 >>>> >>  ..- attr(*, "names")= chr [1:4] "object" "subset" "target" "value"
 >>>> >>  ..- attr(*, "package")= chr [1:4] "oligoClasses" "methods" "methods" 
 >>>> >> "methods"
 >>>> >> $ mnames   : chr [1:2] "object" "value"
 >>>> >> $ fnames   : chr [1:4] "object" "subset" "target" "value"
 >>>> >> [1] "f"          "fdef"       "fnames"     "fsig"       "imf"
 >>>> >> [6] "method"     "mnames"     "omitted"    "omittedSig" "sig0"
 >>>> >> [11] "sigNames"   "signature"
 >>>> >> List of 2
 >>>> >> $ omittedSig: logi [1:4] FALSE TRUE TRUE FALSE
 >>>> >> $ signature : Named chr [1:4] "TilingFeatureSet" "ANY" "ANY" "array"
 >>>> >>  ..- attr(*, "names")= chr [1:4] "object" "subset" "target" "value"
 >>>> >>  ..- attr(*, "package")= chr [1:4] "oligoClasses" "methods" "methods" 
 >>>> >> "methods"
 >>>> >> Error in omittedSig && (signature[omittedSig] != "missing") :
 >>>> >>  'length(x) = 4 > 1' in coercion to 'logical(1)'
 >>>> >> Error: unable to load R code in package 'oligo'
 >>>> >>
 >>>> >
 >>>> > Thank you, Henrik, nice piece of using trace() .. and the above
 >>>> > is useful for solving the issue --  I can work with that.
 >>>> >
 >>>> > I'm  already pretty sure the wrong code starts with
 >>>> >
 >>>> >    omittedSig <- sigNames %in% fnames[omitted] # ....
> 
>     >> my  "pretty sure"  statement above has proven to be wrong ..
> 
 >>>> > -------------
 >>>> >
 >>>>
 >>>> I think the intention must have been that the two "ANY" signatures should 
 >>>> change to "missing".
> 
>     >> Definitely.
> 
 >>>> However, with the current logic that will not happen, because
 >>>>
 >>>> > c(F,T,T,F) &&  c(T,T)
 >>>> [1] FALSE
 >>>>
 >>>> Henrik's non-fix would have resulted in
 >>>>
 >>>> > c(F,T,T,F) &  c(T,T)
 >>>> [1] FALSE  TRUE  TRUE FALSE
 >>>>
 >>>> which is actually right, but only coincidentally due to recycling of 
 >>>> c(T,T). Had it been c(F,T) then it would have been expanded to c(F,T,F,T) 
 >>>> which would be the opposite of what was wanted.
 >>>>
 >>>> Barring NA issues, I still think
 >>>>
 >>>> omittedSig[omittedSig] <- (signature[omittedSig] != "missing")
 >>>>
 >>>> should do the trick.
> 
>     >> yes, (most probably).  I've found a version of that which should
>     >> be even easier to "read and understand", in  svn commit 76753 :
> 
>     >> svn diff -c 76753 src/library/methods/R/RMethodUtils.R
> 
>     >> --- src/library/methods/R/RMethodUtils.R (Revision 76752)
>     >> +++ src/library/methods/R/RMethodUtils.R (Revision 76753)
>     >> @@ -342,8 +342,7 @@
>     >> gettextf("formal arguments (%s) omitted in the method definition 
> cannot be in the signature", bad2),
>     >> call. = TRUE, domain = NA)
>     >> }
>     >> -    else if(!all(signature[omittedSig] == "missing")) {
>     >> -        omittedSig <- omittedSig && (signature[omittedSig] != 
> "missing")
>     >> +    else if(any(omittedSig <- omittedSig & signature != "missing")) {
> 
> 
>     >> BTW:  I've marked this --- and the  runmed() seg.fault + na.action
>     >> change ---  as something to be added to R 3.6.1 patched,  as I
>     >> deemed I should obey the "code freeze" rule in both cases.
> 
>     >> Martin
> 
>     > Hmm... I think we got a 'Neverending Story' here -- because it
>     > seems, both Peter and I were wrong in thinking that it's a good
>     > idea to change "missing" to "ANY" here ...
>     > ((or if that *was* correct, that needs to entail more changes
>     > happening during setMethod(.) {conformMethod() is only called in
>     > one place in our code base, namely from setMethod()} :
> 
> as a matter of fact, I've been brave for now, left the change to
> conformMethod()  and started to fix the constructed .local()
> calls which are created in  conformMethod()'s sibling,
> which is rematchDefinition().
> 
> It seems that this builds e.g. Matrix {with its gazillion
> setMethod()s} and that continues to run its own tests.  OTOH,
> Matrix may not trigger the situations that are dealt with here
> at all, as the signature() are rarely longer than three, and at
> some point in time I had made long passes through the package in
> order to "minimize" the .local() calls.
> 
> --> svn commit 76756  (in addition to 76753, mentioned earlier)
>     now has rematchDefinition() changes
> 
> I would be positively surprised if (but can imagine that) this
> had no affect on CRAN / Bioconductor packages.
> 
> Still, these two changes seem to achieve what both the comments
> and the documentation of  conformMethod() and rematchDefinition()
> suggest should happen.
> 
> Of course, I'd really be happy if people with S4 packages would
> check them with an R-devel version with svn rev >=  76756
> and report problems they see.
> I do imagine effects, and would expect that bugs in current code
> become visible where they had not done so previously.
> 
> Martin
> 
>     > I've started to explore the effects of the change using and
>     > extending the tests/reg-tests-1d.R  example that I had just committed.
> 
>     > And the result is *not good* :
> 
>     > As we said above, the new code does replace all "ANY" by "missing" in 
> the
>     > signature, unless the "ANY" are at the end of the signature.
> 
>     > However, later methods package code producing the .local(.)
>     > calls in the method definition (in cases where the signature of
>     > the generic and the method do not match exactly) --- possibly
>     > may have been tweaked later than the conformMethod() code ---
>     > and the .local() calls they now produce
> 
>     > - work as intended for R <= 3.6.0 (and R 3.6.1 RC)
>     > - fail to work for R-devel with the change :
> 
>     > See this (not a minimal rep.rex. but one building on Henrik's
>     > oligo case and what's newly in  tests/reg-tests-1d.R ) :
> 
>     > 
> -----------------------------------------------------------------------------
> 
>     > ## conformMethod()  "&& logic" bug, by Henrik Bengtsson on R-devel 
> list, 2019-06-22
>     > setClass("tilingFSet", slots = c(x = "numeric"))
>     > if(!is.null(getGeneric("oligoFn"))) removeGeneric("oligoFn")
>     > setGeneric("oligoFn",
>     > function(object, subset, target, value) { standardGeneric("oligoFn") })
>     > Sys.unsetenv("_R_CHECK_LENGTH_1_LOGIC2_") ## << added here, to compare 
> with R 3.6.0, 3.5.3, ..
>     > setMethod("oligoFn", signature(object = "tilingFSet", value="array"),   
>   ## Method _ 1 _
>     > function(object, value) { list(object=object, value=value) })
>     > setMethod("oligoFn", signature(object = "matrix", target="array"),      
>   ## Method _ 2 _
>     > function(object, target) list(object=object, target=target))
>     > setMethod("oligoFn", signature(object = "matrix", subset="integer"),    
>   ## Method _ 3 _
>     > function(object, subset) list(object=object, subset=subset))      #     
>   (*no* Note: ANY at end)
>     > setMethod("oligoFn", signature(object = "matrix"),                      
>   ## Method _ 4 _
>     > function(object) list(object=object))                             #     
>   (*no* Note: ANY at end)
>     > showMethods("oligoFn") # F.Y.I.:  in R 3.6.0 and earlier: contains 
> "ANY" everywhere
> 
>     > ##-- Now, the following *DOES* work fine in R <= 3.6.0  but *no longer* 
> in R-devel :
>     > str(r1 <- oligoFn(object=new("tilingFSet"), value=array(2)))
>     > str(r2 <- oligoFn(object=diag(2),          target=array(42)))
>     > ## These 2 work fine in all versions of R: Here the "ANY" remain at the 
> end:
>     > str(r3 <- oligoFn(object=diag(2),          subset=1:3))
>     > str(r4 <- oligoFn(object=diag(2)))
> 
>     > 
> -----------------------------------------------------------------------------
>     > The two errors in R-devel are actually quite user-confusing:
> 
>     >> r2 <- oligoFn(object=diag(2),          target=array(42))
>     > Error in .local(object, target) :
>     > argument "target" is missing, with no default
>     >> getMethod("oligoFn", signature(object="matrix", subset="missing", 
> target="array"))
>     > Method Definition:
> 
>     > function (object, subset, target, value)
>     > {
>     > .local <- function (object, subset, target, value)
>     > list(object = object, target = target)
>     > .local(object, target)
>     > }
> 
>     > Signatures:
>     > object   subset    target  value
>     > target  "matrix" "missing" "array" "ANY"
>     > defined "matrix" "missing" "array" "ANY"
>     >>
> 
> 
>     > My conclusion:  There's something really wrong with what
>     > conformMethod() has been *intended* to achieve and what it
>     > "accidentally" did achieve in these cases: it never replaced
>     > "ANY" by "missing" in all these cases *AND* that is what it
>     > seems it should continue doing.
> 
>     > BTW: ?conformMethod  goes to a page with quite a few things,
>     > relevantly containing
> 
>     > ‘conformMethod’: If the formal arguments, ‘mnames’, are not
>     > identical to the formal arguments to the function, ‘fnames’,
>     > ‘conformMethod’ determines whether the signature and the two
>     > sets of arguments conform, and returns the signature,
>     > possibly extended.  The function name, ‘f’ is supplied for
>     > error messages. The generic function, ‘fdef’, supplies the
>     > generic signature for matching purposes.
> 
>     > The method assignment conforms if method and generic function
>     > have identical formal argument lists.  It can also conform if
>     > the method omits some of the formal arguments of the function
>     > but: (1) the non-omitted arguments are a subset of the
>     > function arguments, appearing in the same order; (2) there
>     > are no arguments to the method that are not arguments to the
>     > function; and (3) the omitted formal arguments do not appear
>     > as explicit classes in the signature.  A future extension
>     > hopes to test also that the omitted arguments are not assumed
>     > by being used as locally assigned names or function names in
>     > the body of the method.
> 
>     > ---
>     > It seems my commit to R-devel needs another change.
>     > This has to wait for hours currently, though.
> 
>     > Martin
> 
>     > ______________________________________________
>     > R-devel@r-project.org mailing list
>     > https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to