【问题标题】:Why does method inheritance kill additional arguments?为什么方法继承会杀死额外的参数?
【发布时间】:2018-07-24 18:03:43
【问题描述】:

我想在我的泛型中设置一些标志(调用UseMethod(),我知道很多:)),然后在方法中使用和/或更新这些标志。

像这样:

g <- function(x) {
  y <- 10
  UseMethod("g")
}
g.default <- function(x) {
  c(x = x, y = y)
}
g.a <- function(x) {
  y <- 5  # update y from generic here
  NextMethod()
}

这在直接跳转到默认方法时有效:

g(structure(.Data = 1, class = "c"))  # here y is never updated
# x  y 
# 1 10 

但是当我通过NextMethod()时,y神秘地消失了:

g(structure(.Data = 1, class = "a"))  # here y is updated, but cannot be found
# Error in g.default(structure(.Data = 1, class = "a")) : 
#  object 'y' not found

已经想出了如何解决这个问题,只是通过y 转了很多次:

f <- function(x, ...) {
  y <- 10
  UseMethod("f")
}
f.default <- function(x, ..., y = 3) {
  c(x = x, y = y)
}
f.a <- function(x, ...) {
  y <- 5
  NextMethod(y = y)
}

产生

f(structure(.Data = 1, class = "c"))
# x y 
# 1 3 
f(structure(.Data = 1, class = "a"))
# x y 
# 1 5 

我的问题是:为什么上面的g().*-example 中的NextMethod() 会杀死额外的y 参数

我认为UseMethod()NextMethod() 的全部意义在于将所有对象从一个调用传递到另一个调用, 不必手动传递它们:

NextMethod 通过为下一个方法创建一个特殊的调用框架来工作。如果没有提供新参数,则参数的数量、顺序和名称将与当前方法的参数相同,但它们的值将被承诺在当前方法和环境中评估它们的名称。

我特别困惑UseMethod() 似乎确实传递了y,但NextMethod() 没有。

【问题讨论】:

  • 与关于UseMethod 的段落相反,引用并没有说传递了局部变量。它仅指参数,更具体地说是关于它们作为承诺传递。传递局部变量可能会降低性能并且是不寻常的(为什么需要这样做?)。没有被杀死;函数环境的内容根本就不传了。
  • 明确说明要传递给函数的内容总是更好,因此您的解决方案对我来说似乎很好。
  • 我的心智模型是泛型正在做调度的工作。然后,该方法向泛型发出信号,告知其邻居将完成工作。从这个角度来看,这并不矛盾(尽管实际情况并非如此)。
  • 我认为关键可能在于“NextMethod 通过为下一个方法创建一个特殊的调用框架来工作”。 UseMethod 将泛型调用为调用环境,因此其变量位于搜索路径上,但 NextMethod 显然正在创建某种单独的环境。我想?
  • 例如这是(function(){x = 5; (function() x)()})()(function(){x = 5; eval(expression((function() x)()), envir = globalenv())})() 之间的区别

标签: r oop inheritance class-method


【解决方案1】:

正如@Roland 指出的那样,这种行为已记录在案:

来自help("UseMethod")关于UseMethod()的段落注释(强调添加):

UseMethod 创建一个新的函数调用,其参数在进入泛型时匹配。 在调用 UseMethod 之前定义的任何局部变量都将保留(与 S 不同)。 在调用 UseMethod 之后的任何语句都不会被评估,因为 UseMethod 不会返回。

关于NextMethod()(上面已经引用)的相应段落仅说明:

NextMethod 通过为下一个方法创建一个特殊的调用框架来工作。如果没有提供新参数,则参数的数量、顺序和名称将与当前方法的参数相同,但它们的值将被承诺在当前方法和环境中评估它们的名称。任何与 ... 匹配的命名参数都经过特殊处理:它们要么替换现有的同名参数,要么附加到参数列表中。它们作为作为参数提供给当前环境的 Promise 传递。 (S 的做法不同!)如果它们已经在当前(或以前的环境)中被评估过,它们仍然被评估过。 (这是一个复杂的领域,可能会发生变化:请参阅“R 语言定义”草案。)

简而言之,UseMethod() 做了一些特别的事情:它传递局部变量NextMethod(),像往常一样,不这样做。

UseMethod() 是例外,而不是 NextMethod()

【讨论】:

    猜你喜欢
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多