setClass('Seq', representation(data = 'character', id = 'character'),
validity = function (object) is_dna(object@data))
print_fasta = function (object) {
if (length(object@id) > 0) cat('>', object@id, '\n', sep = '')
cat(strsplit(object@data, '(?<=.{60})', perl = TRUE)[[1]],
sep = '\n')
}
setMethod('show', signature('Seq'), print_fasta)
## [1] "show"
setGeneric('revcomp',
function (object) new('Seq', data = rc(object@data), id = object@id))
## [1] "revcomp"
(gattaca_s4 = new('Seq', data = 'GATTACA', id = 'from the movie'))
## >from the movie
## GATTACA
## >from the movie
## TGTAATC
seq = function (data, id) {
stopifnot(is_dna(data))
stopifnot(inherits(id, 'character'))
structure(as.list(environment()), class = 'seq')
}
print.seq = function (x, ...) {
if (length(x$id) > 0) cat('>', x$id, '\n', sep = '')
cat(strsplit(x$data, '(?<=.{60})', perl = TRUE)[[1]], sep = '\n')
}
revcomp = function (seq) UseMethod('revcomp')
revcomp.default = rc
revcomp.seq = function (seq)
seq(revcomp(seq$data), seq$id)
(gattaca_s3 = seq('GATTACA', 'from the movie'))
## >from the movie
## GATTACA
## >from the movie
## TGTAATC
Here’s a “better” pseudo-S4 that emphasises functions instead of data (as it should, in a functional language), and scaffolds S3 code behind the scenes, but with S4-like type checks in place:
To show that this is reasonable, here’s a quick and dirty proof of concept implementation of
class_
. In reality, I’d probably call this functionclass
and design it so that existing use ofclass
(i.e. returning or assigning an object’s S3 class) would still work. This is messy but entirely possible. A real version would also need to allow for inheritance and potentially a cleaner interface.