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

Popular posts from this blog

angularjs - ADAL JS Angular- WebAPI add a new role claim to the token -

php - CakePHP HttpSockets send array of paramms -

node.js - Using Node without global install -