Is it ok from architectural point of view to dispatch the constructor in R (S3 system)?
I have a constructor for class returns and I want to dispatch it in a way like: returns.zoo, returns.data.frame etc.
Just my opinion, but I think there is (unwritten) convention to use as prefix in this case. For example: as.data.frame coerces various objects to a data frame.
Same with as.matrix, as.Date and as.list ...
Often a "non-as" function calls the generic as function (e.g. data.frame function calls as.data.frame).
There is also a good practice to implement a function with is prefix.
For example: is.data.frame, is.list.
But sometimes this is not so. For example formula is a generic "coercer"
and as.formula is not. And there are a lot of packages with combined practice. For example igraph includes as.igraph generic but uses from_data_frame to create object from a data frame.
So I guess as.returns.zoo will look aligned with existing practice but
returns.zoo is not wrong either.
Related
There are a number of tests which, applied to an object of a given class, produce information about that object. Consider objects of class "function". The functions is.primitive() or is.closure(), or (from rlang) is_primitive_eager() or is_primitive_lazy(), provide information about a function object. However, Using methods(class = "function") (with rlang loaded) does not return any of these functions:
[1] as.data.frame as.list coerce coerce<- fortify head latex plot print tail .
Using extends(class1 = "function", maybe = TRUE, fullInfo = TRUE) shows two superclasses, "OptionalFunction" and "PossibleMethod".
Using completeClassDefinition(Class = "function", doExtends=TRUE) provides 23 subclasses. However, it appears to me (though I am not sure of this) that all or almost all of the super- and sub-classes from these two functions are specifically of S4 classes, which I generally do not use. One of these subclasses is "genericFunction", so I tried to apply it to a base R function which I knew to be generic. Although is(object=plot, class2 = "genericFunction") returns TRUE, and plot() antedates S4 classes, there is no "is.generic" test in base R, but there is an "isGeneric" test in the methods package, which suggests to me that plot() has been rewritten as an S4 object.
At any rate, there are a lot of obvious potential properties of functions, like whether they are generic, for which there are no is.<whatever> tests that I can find, and I would like to know if there are other ways I can search for them, e.g., in packages.
A more generic way of asking this same question is whether there is any way of identifying functions that will accept objects of a specified class and not return an error or nonsense. If so I could take a list of the functions in the reccomended packages or in some specified package and test whether each returns a sensable response when handed a function. This is not exactly an answer --- such a method would return TRUE for quote(), for example -- but it would at least cut the problem down to size.
I store important metadata in R objects as attributes. I want to migrate my workflow to Julia and I am looking for a way to represent at least temporarily the attributes as something accessible by Julia. Then I can start thinking about extending the RData package to fill this data structure with actual objects' attributes.
I understand, that annotating with things like label or unit in DataFrame - I think the most important use for object' attributes - is probably going to be implemented in the DataFrames package some time (https://github.com/JuliaData/DataFrames.jl/issues/35). But I am asking about about more general solution, that doesn't depend on this specific use case.
For anyone interested, here is a related discussion in the RData package
In Julia it is ideomatic to define your own types - you'd simply make fields in the type to store the attributes. In R, the nice thing about storing things as attributes is that they don't affect how the type dispatches - e.g. adding metadata to a Vector doesn't make it stop behaving like a Vector. In julia, that approach is a little more complicated - you'd have to define the AbstractVector interface for your type https://docs.julialang.org/en/latest/manual/interfaces/#man-interface-array-1 to have it behave like a Vector.
In essence, this means that the workflow solutions are a little different - e.g. often the attribute metadata in R is used to associate metadata to an object when it's returned from a function. An easy way to do something similar in Julia is to have the function return a tuple and assign the result to a tuple:
function ex()
res = rand(5)
met = "uniformly distributed random numbers"
res, met
end
result, metadata = ex()
I don't think there are plans to implement attributes like in R.
I come from a C# background and try to migrate some of my time series library to R.
One of the benefits of OOP is that I can tuck away variables in a class and pass this as reference.
I read up on R environments, lists, ... and I'm still not sure about the right approach. If I would use a list then I would need to check the function argument:
exists()
(btw: Is there also a function to test for the elements in a list)
I could create a list, pass it as an argument and then write the result back in a list. But is this the right approach?
Any comments ...
exists is seldom used. If you need it, maybe you do something wrong.
missing is sometimes used.
Functions sometimes, but not very often, receive lists as parameters, and often return lists.
To test whether a list foo has an element bar, use is.null(foo$bar). This is FALSE if the list has the element, TRUE otherwise.
I've been developing a S4 class which is essentially a data.frame with a little bit of extra information. For the purposes of this question, the "extra" features of this class are irrelevant. What matters is that the class contains a data.frame object stored in one of it's slots. (I put the data.frame in a slot, instead of naming it a superclass, because I find that S4 classes which contain data.frames simplify the data.frames to lists for some reason).
Here's a basic example:
setClass('tmp_class', slots = c(df = 'data.frame'))
test_object <- new('tmp_class', df = data.frame(Num = 1:10, Let = letters[1:10]))
Now what I'd like to do is make it so that essentially any function applied to an object of this class is applied to the data.frame in slot #df. It's easy to write methods for specific functions to do this, like:
setMethod('dim', signature = c(x = 'tmp_class'), function(x) dim(x#df))
But I'm limited to only the functions I can think of, and any function invented by a user wouldn't work.
It is a simple matter to write a sort of wrapper/closure to modify a function to work on my class, like this:
tmp_classize <- function(func){
function(tmp, ...){ func(tmp#df, ...) }
}
So, rather than writing methods for, say, colnames() or ncol(), I could just run:
tmp_classize(colnames)(test_object)
or
tmp_classize(ncol)(test_object)
But what I'd like to do is somehow evoke my "tmp_classize" function on any function applied to my class, automatically. I can't figure out how to do it. I was thinking that if could somehow call a "universal method" with an input signature of class "tmp_class", and then use sys.function() to grab the actual function being called, maybe I could make something work, but A) there are recursion problems B) I don't know how to call such a "universal" method. It seems to me that the solution, if it exists at all, might necessitate non-standard evaluation, which I'd rather avoid, but might use if necessary.
Thanks!
P.S. I realize this undertaking may be unwise/poor programming technique, and I may never actually implement it in a package. Still I'm curious to know if it is possible.
P.P.S. I'd also be interested in the same idea applied to S3 classes!
In principal what you could do is make a classUnion for your class and data.frame and write methods for your class that deal with all of the ways to read and write to data.frames such as $, [, dim(), <- and many more. Then when other functions seek to use your new class as data.frame there will be methods for this to work. This is somewhat explained in John Chambers "Software for Data Analysis" starting on page 375. That said this system may be very difficult to implement.
A simpler system may be to just add an extra attribute to your data.frame with the extra info you need. For example:
x<-data.frame(a=1:3,b=4:6)
attr(x,"Info")<-"Extra info I need"
attributes(x)$Info
[1] "Extra info I need"
This is not as elegant as a S4 class but will do everything a data.frame does. I suspect that someone who is familiar with S3 classes could improve on this idea quite a bit.
The simplest solution is to have your class contain data.frame instead of having it as one of the slots. For example here is a data.frame with a timestamp:
setclass(
"timestampedDF",
slots=c(timestamp="POSIXt"),
contains="data.frame"
)
Now all functions which work for a data.frame (such as head) will automatically work for timestampedDF objects. If you need to get at the "data frame part", then that is held in a hidden slot object#.Data.
I'd like to be able to view the structure of objects in Matlab/GNU Octave the same way as I do in R (using the str() function). Is there a function that does this? An example task would be returning nr rows and cols in matrix, but also all the arguments for a given function.
I'm aware that I could use both size() and help() (but not for function files) separately to get this information.
There are several useful functions for displaying some information about Matlab objects (I can't say anything about Octave compatibility), but I'm not sure they'll provide the same detail as R's str(). You can display all of the methods of a class with the methods function, e.g.:
methods('MException')
which returns
Methods for class MException:
addCause getReport ne throw
eq isequal rethrow throwAsCaller
Static methods:
last
The what function will return similar results. Or methods can be used on an object of a given class:
ME = MException('Test:test','Testing');
methods(ME)
Similarly, you can view the properties with properties and the events with events.