如何找到 class 的默认构造方法
How to find the default construstor methods for a class
问题来自试验一个包,发现使用 new(Class = 'ddmatrix', Data = X)
和 ddmatrix(Data = X)
会产生不同的结果,其中 X
是一个矩阵(可以认为 class ddmatrix
是转换后的 Class matrix
).
文档
包中定义了一个S4classddmatrix
。 setGeneric(name = 'ddmatrix')
的通用构造函数。此外,包定义 setMethod('ddmatrix', signature = 'matrix', ...)
如下:
setMethod("ddmatrix", signature(data="matrix"),
function(data, nrow=1, ncol=1, byrow=FALSE, ...
bldim=.pbd_env$BLDIM, ICTXT=.pbd_env$ICTXT)
{
dim(data) <- NULL
ret <- ddmatrix(data=data, nrow=nrow, ncol=ncol, byrow=byrow, bldim=bldim, ICTXT=ICTXT)
return( ret )
}
)
我很困惑如何在上面的 setMethod('ddmatrix', signature = 'matrix')
步骤中使用方法 ddmatrix
。这个 ddmatrix
方法是泛型 ddmatrix
的默认方法吗?
同时,当调用 new('ddmatrix', Data = X)
时,它将调用哪个方法从 matrix
对象构建新的 ddmatrix
对象? new
函数为:
function (Class, ...)
{
ClassDef <- getClass(Class, where = topenv(parent.frame()))
value <- .Call(C_new_object, ClassDef)
initialize(value, ...)
}
问题
要回答new('ddmatrix')
和ddmatrix()
之间的差异,我认为一种方法是找到默认构造函数。同时,包中还定义了setMethod('ddmatrix', signature = 'vector',...)
,这是默认的吗?
在某种程度上,这取决于作者。许多人认为 new()
和 @
或 slot()
(用于插槽访问)严格针对包开发人员——这些将实现细节直接暴露给用户——并且更喜欢编写构造函数和将接口置于实现之上的访问器。这似乎是您正在考虑的包的情况,其中 ddmatrix()
是面向用户的构造函数。
作者似乎实现了外观模式,其中几种不同的方法在调用另一个函数/方法进行实际对象构造之前进行相对较小的数据转换。从您展示的内容来看,ddmatrix,matrix-method 似乎调用了 ddmatrix,vector-method(因为在 ddmatrix,matrix-method 中函数设置 dim(data) <- NULL
,将矩阵转换为向量,然后调用 ddmatrix()
现在分派给 vector 方法),并通过 https://github.com/RBigData/pbdDMAT/blob/master/R/constructors.r#L191 处的 new()
构造对象。不同的包作者可能采用不同的设计,其中几个方法分别调用 new()
.
文档通常也有帮助,例如,?ddmatrix
不讨论通过 new()
直接构建对象。
这是一个更简单的例子。我创建了一个 class "A",其中一个插槽包含一个数字向量
setClass("A", slots=c(x="numeric"))
这里我创建了一个构造函数,因为我希望用户看到 class 的接口,而不是它的实现
A = function(x=numeric())
new("A", x=x)
至此,A()
和new("A")
return一个结构相同的对象,例如
> new("A")
An object of class "A"
Slot "x":
numeric(0)
> A()
An object of class "A"
Slot "x":
numeric(0)
也许作为 "A" class 的开发者,我希望 class 'A' 的未初始化对象具有 'NA' 作为插槽 x,所以我修改
A = function(x = NA_real_)
new("A", x=x)
现在直接调用 new()
returns 与调用 A()
不同的对象
> new("A")
An object of class "A"
Slot "x":
numeric(0)
> A()
An object of class "A"
Slot "x":
[1] NA
哪个是'correct'?嗯,两者都是正确的,但作为 class 的创建者,我打算让用户通过调用函数 A()
.[=37 来创建 class "A" 的对象=]
将接口(使用A()
构造对象)与实现(使用new()
构造对象)分开的一个典型原因是实现对用户而言并不明显。 ddmatrix()
函数似乎就是这种情况——出于只有包作者需要知道的原因,将 R 矩阵存储为包含维度信息的向量会很方便。我想一个简单的等价物可能是
setClass("A", slots=c(data="numeric", nrow="integer", ncol="integer"))
A = function(m=matrix(0, 0, 0)) {
stopifnot(is(m, "matrix"))
new("A", data=as.vector(m), nrow=nrow(m), ncol=ncol(m))
}
例如
> A(matrix(1:10, 5))
An object of class "A"
Slot "data":
[1] 1 2 3 4 5 6 7 8 9 10
Slot "nrow":
[1] 5
Slot "ncol":
[1] 2
作者为什么要这样做?作为用户,这对我们来说并不重要。为什么我们不能通过调用 m = matrix(1:10, 5); new("A", data=as.vector(m), nrow=nrow(m), ncol(m))
创建相同的对象?我们可以,但是当作者决定更改他们的实现以便存储每行开头的偏移量时,我们必须了解作者所做的并更新我们的代码。
问题来自试验一个包,发现使用 new(Class = 'ddmatrix', Data = X)
和 ddmatrix(Data = X)
会产生不同的结果,其中 X
是一个矩阵(可以认为 class ddmatrix
是转换后的 Class matrix
).
文档
包中定义了一个S4classddmatrix
。 setGeneric(name = 'ddmatrix')
的通用构造函数。此外,包定义 setMethod('ddmatrix', signature = 'matrix', ...)
如下:
setMethod("ddmatrix", signature(data="matrix"),
function(data, nrow=1, ncol=1, byrow=FALSE, ...
bldim=.pbd_env$BLDIM, ICTXT=.pbd_env$ICTXT)
{
dim(data) <- NULL
ret <- ddmatrix(data=data, nrow=nrow, ncol=ncol, byrow=byrow, bldim=bldim, ICTXT=ICTXT)
return( ret )
}
)
我很困惑如何在上面的 setMethod('ddmatrix', signature = 'matrix')
步骤中使用方法 ddmatrix
。这个 ddmatrix
方法是泛型 ddmatrix
的默认方法吗?
同时,当调用 new('ddmatrix', Data = X)
时,它将调用哪个方法从 matrix
对象构建新的 ddmatrix
对象? new
函数为:
function (Class, ...)
{
ClassDef <- getClass(Class, where = topenv(parent.frame()))
value <- .Call(C_new_object, ClassDef)
initialize(value, ...)
}
问题
要回答new('ddmatrix')
和ddmatrix()
之间的差异,我认为一种方法是找到默认构造函数。同时,包中还定义了setMethod('ddmatrix', signature = 'vector',...)
,这是默认的吗?
在某种程度上,这取决于作者。许多人认为 new()
和 @
或 slot()
(用于插槽访问)严格针对包开发人员——这些将实现细节直接暴露给用户——并且更喜欢编写构造函数和将接口置于实现之上的访问器。这似乎是您正在考虑的包的情况,其中 ddmatrix()
是面向用户的构造函数。
作者似乎实现了外观模式,其中几种不同的方法在调用另一个函数/方法进行实际对象构造之前进行相对较小的数据转换。从您展示的内容来看,ddmatrix,matrix-method 似乎调用了 ddmatrix,vector-method(因为在 ddmatrix,matrix-method 中函数设置 dim(data) <- NULL
,将矩阵转换为向量,然后调用 ddmatrix()
现在分派给 vector 方法),并通过 https://github.com/RBigData/pbdDMAT/blob/master/R/constructors.r#L191 处的 new()
构造对象。不同的包作者可能采用不同的设计,其中几个方法分别调用 new()
.
文档通常也有帮助,例如,?ddmatrix
不讨论通过 new()
直接构建对象。
这是一个更简单的例子。我创建了一个 class "A",其中一个插槽包含一个数字向量
setClass("A", slots=c(x="numeric"))
这里我创建了一个构造函数,因为我希望用户看到 class 的接口,而不是它的实现
A = function(x=numeric())
new("A", x=x)
至此,A()
和new("A")
return一个结构相同的对象,例如
> new("A")
An object of class "A"
Slot "x":
numeric(0)
> A()
An object of class "A"
Slot "x":
numeric(0)
也许作为 "A" class 的开发者,我希望 class 'A' 的未初始化对象具有 'NA' 作为插槽 x,所以我修改
A = function(x = NA_real_)
new("A", x=x)
现在直接调用 new()
returns 与调用 A()
> new("A")
An object of class "A"
Slot "x":
numeric(0)
> A()
An object of class "A"
Slot "x":
[1] NA
哪个是'correct'?嗯,两者都是正确的,但作为 class 的创建者,我打算让用户通过调用函数 A()
.[=37 来创建 class "A" 的对象=]
将接口(使用A()
构造对象)与实现(使用new()
构造对象)分开的一个典型原因是实现对用户而言并不明显。 ddmatrix()
函数似乎就是这种情况——出于只有包作者需要知道的原因,将 R 矩阵存储为包含维度信息的向量会很方便。我想一个简单的等价物可能是
setClass("A", slots=c(data="numeric", nrow="integer", ncol="integer"))
A = function(m=matrix(0, 0, 0)) {
stopifnot(is(m, "matrix"))
new("A", data=as.vector(m), nrow=nrow(m), ncol=ncol(m))
}
例如
> A(matrix(1:10, 5))
An object of class "A"
Slot "data":
[1] 1 2 3 4 5 6 7 8 9 10
Slot "nrow":
[1] 5
Slot "ncol":
[1] 2
作者为什么要这样做?作为用户,这对我们来说并不重要。为什么我们不能通过调用 m = matrix(1:10, 5); new("A", data=as.vector(m), nrow=nrow(m), ncol(m))
创建相同的对象?我们可以,但是当作者决定更改他们的实现以便存储每行开头的偏移量时,我们必须了解作者所做的并更新我们的代码。