Note
Fields can also be supplied as a vector (we use a list in the example). Using a vector does not allow to specify a type. It looks as follows:
setRefClass(“account”, fields = c(“ref_number”, “holder”, “branch”, “opening_date”, “account_type” ) )
Hint
It is possible to leave the input type undecided by not providing a type in the list environment. This could look like this:
setRefClass(“account”, fields = list(holder, # accepts all typesbranch, # accepts all typesopening_date = “Date” # dates only) )
Let us now explore this object that was returned by the function setRefClass()
.
isS4(account) ## [1] TRUE # account is S4 and it has a lot more than we have defined:account ## Generator for class “account”: ## ## Class fields: ## ## Name: ref_number holder branch ## Class: numeric character character ## ## Name: opening_date account_type ## Class: Date c haracter ## ## Class Methods: ## “field”, “trace”, “getRefClass”, “initFields”, ## “copy”, “callSuper”, “.objectPackage”, “export”, ## “untrace”, “getClass”, “show”, “usingMethods”, ## “.objectParent”, “import” ## ## Reference Superclasses: ## “envRefClass”
The object returned by setRefClass
(or retrieved later by getRefClass
) is called a generator object . This object automatically gets the following methods.
generator object
new to create instances of the class. Its arguments are the named arguments specifying initial values for the fields;
methods to add methods or modify existing;
help to get help about the methods;
fields to get a list of attributes (fields) of that class;
lock to lock the named fields so that their value can only be set once;
accessors sets up accessor-methods in form of getxxx and setxxx (where “xxx” is replaced by the field names).
Refclass objects are mutable, or in other words, they have reference semantics. To understand this, we shall create the current account class and the investment account class.
custBank <- setRefClass(“custBank”, fields = list(name = “character”, phone = “character” ) ) invAccount <- setRefClass(“invAccount”, fields = list(custodian = “custBank”), contains = c(“account”) # methods go here)
Let us now come back to the current account and define it while adding some methods (though as we will see later, it is possible to add them later too).
# Definition of RC object currentAccountcurrAccount <- setRefClass(“currentAccount”, fields = list(interest_rate = “numeric”, balance = “numeric”), contains = c(“account”), methods = list( credit = function(amnt) { balance <<-balance +amnt }, debet = function(amnt) { if(amnt <=balance) { balance <<-balance -amnt } else{ stop(“Not rich enough!”) } } ) ) # note how the class reports on itself:currAccount ## Generator for class “currentAccount”: ## ## Class fields: ## ## Name: ref_number holder branch ## Class: numeric character character ## ## Name: opening_date account_type interest_rate ## Class: Date character numeric ## ## Name: balance ## Class: numeric ## ## Class Methods: ## “debet”, “credit”, “import”, “.objectParent”, ## “usingMethods”, “show”, “getClass”, “untrace”, ## “export”, “.objectPackage”, “callSuper”, “copy”, ## “initFields”, “getRefClass”, “trace”, “field” ## ## Reference Superclasses: ## “account”, “envRefClass”
Note – Assigning in the encapsulating environment
Notice that, the assignment operator within an object is the local assignment operator: <<-
. The operator <<-
will call the accessor functions if defined (via the object$accessors()
function).
We can now create accounts and use the methods supplied.
ph_acc <-currAccount $new(ref_number = 321654987, holder = “Philippe”, branch = “LDN05”, opening_date = as.Date( Sys.Date()), account_type = “current”, interest_rate = 0.01, balance = )
Now, we can start using the money and withdrawing money.
ph_acc $balance # after creating balance is 0:## [1] 0 ph_acc $debet(200) # impossible (not enough balance) ## Error in ph_acc$debet(200): Not rich enough!ph_acc $credit(200) # add money to the accountph_acc $balance # the money arrived in our account## [1] 200 ph_acc $debet(100) # this is possibleph_acc $balance # the money is indeed gone## [1] 100
Note – Addressing attributes and methods
The Reference Class OO implementation R5 uses the $
to access attributes and methods.
It is also possible – though not recommendable – to create methods after creation of the class.
alsoCurrAccount <- setRefClass(“currentAccount”, fields = list( interest_rate = “numeric”, balance = “numeric”), contains = c(“account”) ) alsoCurrAccount $methods( list( credit = function(amnt) { balance <<-balance +amnt }, debet = function(amnt) { if(amnt <=balance) { balance <<-balance -amnt } else{ stop(“Not rich enough!”) } } ))
Note – No dynamic editing of field definitions
In general, R is very flexible in how any of the OO systems is implemented. However, the refclasses do not allow to add fields after creating. This makes sense because it would make all existing objects invalid, since they would not have those new fields.
6.4.2 Important Methods and Attributes
All refclass object inherit from the same superclass envRefClass
, and so they get at creation some hidden fields and methods. For example, there is .self
. This variable refers to the object itself.
Other common methods for R5 objects that are always available (because they are inherited from envRefClass
) are the following, illustrated for an object of RC class named RC_obj
:
RC_obj$callSuper(): This method initializes the values defined in the super-class.
Читать дальше