r - S4 classes: arguments passed to new() don't go into their slots -
i'm building r package s4 classes, , i'm having trouble new
function. have class called configs
setclass("configs", slots = list( burnin = "numeric", chains = "numeric", features = "numeric", iterations = "numeric", mphtol = "numeric", samples = "numeric", seed = "numeric", thin = "numeric", verbose = "numeric" ), prototype = list( burnin = 0, chains = 2, features = 5, iterations = 5, mphtol = 1e-4, samples = 3, seed = sample(1e6, 1), thin = 0, verbose = 0 ) )
and when load part global environment, can create new configs
object slots different defaults.
> new("configs", features = 1000) object of class "configs" slot "burnin": [1] 0 slot "chains": [1] 2 slot "features": [1] 1000 slot "iterations": [1] 5 slot "mphtol": [1] 1e-04 slot "samples": [1] 3 slot "seed": [1] 437211 slot "thin": [1] 0 slot "verbose": [1] 0
however, when install whole package, load fresh environment, , run new("configs", features = 1000)
, features
of 5. why doesn't new()
put values in slots anymore?
my package passed r cmd check
without errors, warnings, or notes. here session info.
> sessioninfo() r version 3.2.0 (2015-04-16) platform: x86_64-unknown-linux-gnu (64-bit) running under: centos release 6.6 (final) locale: [1] lc_ctype=en_us.utf-8 lc_numeric=c [3] lc_time=en_us.utf-8 lc_collate=en_us.utf-8 [5] lc_monetary=en_us.utf-8 lc_messages=en_us.utf-8 [7] lc_paper=en_us.utf-8 lc_name=c [9] lc_address=c lc_telephone=c [11] lc_measurement=en_us.utf-8 lc_identification=c attached base packages: [1] stats graphics grdevices utils datasets methods base other attached packages: [1] heterosis_0.0 pracma_1.8.3 mcmcpack_1.3-3 mass_7.3-40 coda_0.17-1 loaded via namespace (and not attached): [1] tools_3.2.0 grid_3.2.0 lattice_0.20-31
edit: got it, i'm still not satisfied.
it turns out initialize
function causing problems.
setmethod("initialize", "configs", function(.object, ...){ # .object = new("configs", ...) validobject(.object) return(.object) })
when remove it, new
puts things in slots again. i'm glad found problem, don't want remove initialize function entirely. want convenient way call validobject , other error checking too, , initialize
seems proper , appropriate place it. , if uncomment commented line, infinite recursion. how create constructor without breaking new
?
initialize()
dual-purpose -- initialization , copy construction. it's better (also more informative user) provide explicit constructor
.a = setclass("a", representation(x="numeric")) = function(x=numeric(), ...) .a(x=x, ...)
validojbect()
called default initialize method when object creation involves slot assignment, there's no need call explicitly during own initialize method (see below); maybe you'd have
.a = setclass("a", representation(x="numeric"), prototype=prototype(x=na_integer_)) setvalidity("a", function(object) { if (length(object@x) != 1l) "'x' must length 1" else true }) = function(x=na_integer_, ...) ## signature informative -- 'x' integer(1), not '...' ## coercion (e.g., as.integer(), below) , other set-up new("a", x=as.integer(x), ...)
with
> a() object of class "a" slot "x": [1] na > a(x=1) object of class "a" slot "x": [1] 1 > a(x=1:2) error in validobject(.object) : invalid class "a" object: 'x' must length 1
an important caveat validity method not called when there no slots initialized user, prototype()
has defined create valid object (verify validobject(new("a"))
.
for question, validity function correct place 'other error checking'. it's hard write correct initialize method, closer correct is
.b = setclass("b", representation(x="numeric", y="numeric"), prototype=prototype(x=na_integer_, y=na_real_)) setmethod("initialize", "b", function(.object, ..., x=.object@x, y=.object@y) { ## pre-processing, invoke 'next' initialize() method ## base initialize() creates object calls validobject() ## no need explicit test of validity .object <- callnextmethod(.object, ..., x=x, y=y) ## post-processing .object })
this sort of weird construction allows initialize()
continue behave copy constructor
> b = new("b", x=1, y=2) # constructor > initialize(b, x=2) # copy-constructor object of class "b" slot "x": [1] 2 slot "y": [1] 2
which important during class inheritance. can see quite tricky -- in end it's tough , seldom worth effort initialize()
correct.
note haven't fulfilled contract of initialize()
,
setclass("c", representation(x="numeric", y="numeric")) # default initialize()
which acts copy constructor when called new()
> c = new("c", x=1, y=2) > new("c", c, x=2) object of class "c" slot "x": [1] 2 slot "y": [1] 2
versus no copy construction b's implementation
> b = new("b", x=1, y=2) > new("b", b, x=2) object of class "b" slot "x": [1] 2 slot "y": [1] na
Comments
Post a Comment