How do you get S3 methods to work with S4 objects? - oop

I'm writing an S3 method that I want to work with any R object, including S4 objects.
The first thing I don't understand is that S4 classes don't appear to derive from an S4 base class, so given f <- function(x) UseMethod("f") I can't just declare an f.S4 dispatch method and have it pick up all S4 objects. (Although if you unclass an S4 object, it does seem to be given class S4.) How should I manage the dispatching?
It seems that the easiest way to deal with these S4 objects would be to convert them to be lists. Unfortunately, as.list throws an error ("no method for coercing this S4 class to a vector").
This is my test S4 object:
library(gWidgetstcltk)
win <- gwindow()
The functions S3Part and S3Class in the methods package looked promising, but they both throw errors when I use them on win. So, question 2 is: Is there a general way of converting S4 objects to lists?

S4 is a superclass (virtual class, whatever, somebody please chime in with the correct name) that cannot be used directly dispatching. Same for S3 by the way. You can do S3-dispatching for S4 classes the way you do with S3 classes. On a sidenote, if nothing is specified then calling myfun on an S4 object will just lead to the .default function. :
myfun <- function(object, ...) UseMethod("myfun")
myfun.default <- function(object,...){
cat("default method.\n")
print(object)
}
myfun.gWindow <- function(object,...){
cat("Here here...")
print(object)
}
x <- 1:10
myfun(x)
myfun(win)
rm(myfun.gWindow)
myfun(win)
If you want to catch all S4 methods, you can dispatch manually in your .default function or generic function, using isS4(). Adding the dispatching in the .default function allows for automatic S3 dispatching to some S4 classes. If you add it in the generic, you just dispatch to all S4 no-matter-what :
myfun.default <- function(object,...){
if(isS4(object)) myfun.S4(object,...)
else {
cat("default method.\n")
print(object)
}
}
myfun.S4 <- function(object,...){
cat("S4 method\n")
print(object)
}
x <- 1:10
myfun(x)
myfun(win)
Regarding your second question: gWindow is a special case. It also returns an error when tried with str(win). I don't know the exact structure, but it's definitely not a normal S4 object.

Related

Why does `EffectScope.shift` need the type parameter `B`?

The move to the new continuations API in Arrow brought with it a handy new function: shift, in theory letting me get rid of ensure(false) { NewError() } or NewError().left().bind() constructs.
But I'm not sure how to properly use it. The documentation states that it is intended to short-circuit the continuation, and there are no conditionals, so it should always take the parameter, and (in either parlance) "make it a left value", and exit the scope.
So what is the type parameter B intended to be used for? It determines the return type of shift, but shift will not return. Given no more context, B can not be inferred, leading to this kind of code:
val res = either {
val intermediate = mayReturnNull()
if (intermediate == null) {
shift<Nothing>(IntermediateWasNull())
}
process(intermediate)
}
Note the <Nothing> (and ignore the contrived example, the main point is that shifts return type can not be inferred – the actual type parameter does not even matter).
I could wrap shift like this:
suspend fun <L> EffectScope<L>.fail(left: L): Nothing = shift(left)
But I feel like that is missing the point. Any explanations/hints would be greatly appreciated.
That is a great question!
This is more a matter of style, ideally we'd have both but they conflict so we cannot have both APIs available.
So shift always returns Nothing in its implementation, and so the B parameter is completely artificial.
This is something that is true for a lot of other things in Kotlin, such as object EmptyList : List<Nothing>. The Kotlin Std however exposes it as fun <A> emptyList(): List<A> = EmptyList.
For Arrow to stay consistent with APIs found in Kotlin Std, and to remain as Kotlin idiomatic as possible we also require a type argument just like emptyList. This has been up for discussion multiple times, and the Kotlin languages authors have stated that it was decided too explicitly require A for emptyList since that results in the best and most consistent ergonomics in Kotlin.
In the example you shared I would however recommend using ensureNotNull which will also smart-cast intermediate to non-null.
Arrow attempts to build the DSL so that you don't need to rely on shift in most cases, and you should prefer ensure and ensureNotNull when possible.
val res = either {
val intermediate = mayReturnNull()
ensureNotNull(intermediate) { IntermediateWasNull() }
process(intermediate) // <-- smart casted to non-null
}

implementing "this" / "self" in a custom interpreted programming language

I'm working on a custom interpreter for fun ;)
What I have so far is assigning variables, defining and calling functions, arrays, loops, if blocks etc...
I've started adding OOP elements to my language and I'm having trouble implementing the "this" / "self" keyword.
I just cannot figure out a solution to this problem.
I've thought about a few solutions:
a class stores it's instances (as a dictionary) and when the "this" keyword appears, the interpreter ignores "private" and "public" keywords (to call a private method from a public one), creates a call to the method referenced by "this" and returns.
the "this" keyword is a reference which under the hood is the instance itself, but the method access modifiers are dropped for that call. this is similar to the first one, but I cannot think of anything better.
Also it would be nice if you knew C# (primarly) or C++, since I'm heavily relying on OOP to create my interpreter.
heres a small sample of code that I would like to implement:
struct Dog has
pub prop age;
prv def bark() do
println "woof woof";
end
pub def run(dist) do
loop 0 to $dist with "d" do
println ("the dog ran " + string $d) + " meters";
$self.bark();
end
end
end
def main(args) do
new Dog -> $dog;
7 -> $dog.age;
println $dog.age;
$dog.run 30;
end
notice that the bark() method is "prv" (private). I would like to know how can I make the struct be aware of it's instances so I can make the dog bark each time it runs (calling a private method from a public method).
Thanks in advance
Your interpreter is going to need to keep an execution stack and environment (otherwise you wouldn't know where to return to after a method is finished, etc.).
In this execution stack/env, apart from a function pointer/signature, you'd also keep the object the method is being invoked on (if any, remember about static-like functions).
This reference that you'd store would then be also accessed when de-referencing $this. And actually this is both part 1 and 2 of your idea - you could put some kind of checks like visibility of methods etc. there.
Good luck, sounds like a fun project!

`does` versus `but` operators when mixing in a Role into an object in Raku

If I have a Role R defined as:
role R { method answer { 42 } }
What is the difference (if any) between these two lines:
my $a = 'question' does R;
my $b = 'question' but R;
They appear very similar:
say $a.answer; # OUTPUT: «42»
say $b.answer; # OUTPUT: «42»
say $a.WHAT; # OUTPUT: «(Str+{R})»
say $b.WHAT; # OUTPUT: «(Str+{R})»
Is this a case of there being More Than One Way To Do It™, and these both mean the same thing? Or is there a subtle difference that I'm missing?
note:
I understand that does is both an operator and a trait and thus can be used when for compile-time mixins (e.g., class C does R {}) whereas but is only for runtime mixins. I also understand that but can be used with an object (e.g., my $c = 'question' but False) whereas does can only be used with a Role. I'm not asking about either of those differences; my only question is about whether there's a difference when both are used at runtime with a Role. I have read the documentation section on mixing in Role, but didn't see an answer.
Put simply:
does modifies an object in place (and should be used with caution with value types, see note below)
but returns a new object.
When created off of a literal, it's probably not as evident, but when used with another object, it's pretty clear I think:
role R { method answer { 42 } }
my $question = 'question';
my $but = $question but R;
my $does = $question does R;
say $question.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R})
say $does.WHAT;  # (Str+{R})
say $question.WHERE; # 129371492039210
say $but.WHERE; # 913912490323923
say $does.WHERE; # 129371492039210 <-- same as $question's
Notice I cheated a bit and swapped the order of does and but. If I had preserved the order you had, the does would modify $question in place, applying the role, meaning that but would clone $question (with its role) and apply the role (again!):
my $does = $question does R;
my $but = $question but R;
say $does.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R}+{R})
This is because does as an operator is conceptually akin to ++ or +=, that is, designed to be used in a standalone context, for instance
my $foo = …;
given $bar {
when 'a' { $foo does A }
when 'b' { $foo does B }
when 'c' { $foo does B }
}
Using but is conceptually closer to using $foo + 1 — mostly meaningless unless assigned to or passed to something else.
A warning for does and value types
If you use does on a value type (strings, numbers mainly), there is an extremely high likelihood that you will cause unintended side effects. This is because value types (which, e.g., strings are) are supposed to be immutable and substitutable for one other. Note the following:
role Fooish { }
my $foo = 'foo';
$foo does Fooish;
say 'foo'.WHAT; # (Str+{Fooish})
This is a substitution that's happening at compile time (so it won't affect, e.g, 'foobar'.substr(0,3), that happens at runtime), but can cause some truly weird effects if you toss them in a loop:
role Fooish { }
my #a;
#a.push('foo' does Fooish) for ^10;
say #a[0].WHAT; # (Str+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish}
+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish})
Applying multiple rolls takes longer and longer the more you do it, so if you change that to ^100000, be ready to wait a while. OTOH, doing but gives you nice constant time and doesn't pollute the literal. This behavior seems, AFAICT, to be perfectly valid, but definitely something that can catch you unexpectedly.

How to avoid the error "staticCFunction must take an unbound..." in Kotlin Native when a Kotlin callback function is called from C?

This is a general question about callback functions, defined in Kotlin Native, called by C functions.
For argument's sake, let's say I'm trying to walk a directory in a filesystem recursively, using https://linux.die.net/man/3/nftw in Kotlin Native.
(I know there are other ways to do this, using other C functions, but that is not the core of this question.)
nftw() takes a function as a callback:
val directory = "//some/directory"
val callback = kotlinx.cinterop.staticCFunction {
file: CPointer<ByteVar>?,
stat: CPointer<stat>?,
typeFlag: Int,
b: CPointer<FTW>? ->
val fileName = file?.toKString()
println(fileName)
val result = 0
result
}
val depth = 10
val flags = 0
platform.posix.nftw(directory, callback, depth, flags)
This works for listing files via "println()", but as as soon as the lambda contains any captured value, I get the following compiler error:
"kotlinx.cinterop.staticCFunction must take an unbound, non-capturing function or lambda".
My question is: is there any recommended approach on how to
access any non-global state from such a callback?
I did come up with a nasty workaround using a global variable, so that's not what I'm looking for primarily. If there is a commonly accepted solution using #ThreadLocal or something else, please discuss.
For native callbacks in general (not specific to nftw). The C function should accept a void* userData parameter and pass it to the callback when it is called. This allows you to pass local data to the callback, instead of global data.
This is the case even in C/C++.
For this particular case (regardless of language) there isn't really a way to do this without some global data (or JIT but let's not think about it). So any workaround would have to be nasty.
Using #ThreadLocal is a "reasonable nasty" solution.
nftw is just not a well designed C interface.

is.object and the S3 class system

Using the class function allows us to determine the class of an object:
> x = 5
> class(x)
[1] "numeric"
I also understand that we can use the is.object command to determine if an object has a class. However some object types are implicit, that is
> is.object(x)
[1] FALSE
Would it be correct to state that all variables in R are objects and is.object is a test for non-implicit classes only?
Also, how do types fit into this. Naively, I thought that the following piece of code would produce an error:
> x = 5
> class(x) = "fake"
> x = X + 1
> x + 1
[1] 6
attr(,"class")
[1] "fake"
But x still has type "double", still everything still works. Can types be thought of as a superclass that all other objects inherit from?
typeof returns the type of internal C representation, and it is not used for method dispatch. So strictly speaking you can not think of types as "superclasses".
There are instead basic classes (numeric, character, list, function etc) which roughly correspond to the names
returned by typeof, but not always (for example type double is of class numeric, special and closure are of class
function, and class data.frame is of type list!).
With S3 and S4 systems you can build non trivial classes using basic classes (but not necessary extending one of those!! example: setClass("foo", list(a="numeric",b="character") does not extend any of the basic classes).
For objects from these basic classes is.object returns FALSE. As its documentation says, this function provides
a very fast way to check if the object is of user build S3 or S4 class (i.e. not one of basic classes).
After casting x as "fake" your object is formally not of "numeric" class:
is(x, "numeric")
#FALSE
but it is interpretable as basic "numeric" object:
is.numeric(x)
#TRUE
And this is why + works here. So, internally, as #Richie already said the default method interprets x as of
numeric basic class.
This conceptual mess is because of S3 informal treatment of classes. Use S4 instead.
correspondence between typeof(.) and basic class(.):
typeof(.) class(.)
NULL "NULL" "NULL"
1 "double" "numeric"
1:1 "integer" "integer"
1i "complex" "complex"
list(1) "list" "list"
data.frame(x=1) "list" "data.frame"
pairlist(pi) "pairlist" "pairlist"
c "special" "function"
lm "closure" "function"
formals(lm)[[1]] "symbol" "name"
formals(lm)[[2]] "symbol" "name"
y~x "language" "formula"
expression((1))[[1]] "language" "("
(y~x)[[1]] "symbol" "name"
expression(x <- pi)[[1]][[1]] "symbol" "name"
A partial answer to the first question is found in Chapter 2 of the R language defninition
R does not provide direct access to
the computer’s memory but rather
provides a number of specialized data
structures we will refer to as
objects. These objects are referred to
through symbols or variables. In R,
however, the symbols are themselves
objects and can be manipulated in the
same way as any other object.
So, yes, all variables are objects.
is.object seems to be more or less equivalent to function(x) !is.null(attr(x, "class")) but I'm willing to be proved wrong on that.
As for the second question, I think this is what happens:
Since x has class "fake", R looks for a method +.fake in the addition but when it doesn't find one, it resorts to the default method. That default method is based upon underlying C code, which uses typeof(x) (or a C equivalent) to determine what should be done. In this case the type of x is "integer".