Any Way to Determine Which Object Called a Method

Any way to determine which object called a method?

As an option, there is a binding_of_caller gem that allows you to execute code in context of any caller on the call stack (caller, caller's caller and so on). It's useful for inspecting (read do anything at any position on the call stack) call stack in development, as used in better_errors.

Objects of class Binding encapsulate the execution context at some particular place in the code and retain this context for future use.

– http://www.ruby-doc.org/core-2.1.4/Binding.html

Should I mention, this technique should only be used for debugging, fun or educational purposes, because it violates principles of OOP really badly.

Mostly because of eval.

Let's prepare stuff:

require 'binding_of_caller' # I assume, you installed this gem already?

Get the immediate (closest on stack, hence 0) caller instance:

binding.of_caller(0).eval('self')

...or even an immediate calling method:

binding.of_caller(0).eval('__method__')

If you need to get higher up the call stack, use numbers other than 0 for getting a caller's binding.

Awfully hacky. But if you really need this — there you go.

How to find the object that called a method in Java

Checking the callers of a method is a quite common request from inexperienced programmers. I'm surprised that it doesn't appear more often on SO. But it's a really incredibly bad idea (just check out the Java 2 (and perhaps worse earlier) Security Model).

There are few circumstances where it's important to implement this restriction. As Oli Charlesworth say, just don't do it. But let's assume that it is important, but we're not going to do stack inspection.

Let's start by assuming we trust the group. A working but nonsensical approach is to pass to the group an object standing in for the person that only the person can create. (Note Java language access restrictions are class-based. A different instance could create such a stand in, but the code would have to be within the Person class.)

public final class Group { // Can't have a malicious subclass.
public void deregisterPerson(Person.Standin standin) {
Person person = standin.person();
...
}
}
public class Person { // May be subclassed.
public final class Standin { // Could be one per Person.
private Standin() { // Hide constructor from other outer classes.
}
public Person person() {
return Person.this;
}
}
private void groupDeregister(Group group) {
group.deregisterPerson(new Standin());
}
}

If we don't trust the group, then we could extend the stand-in to reference the group. This prevents a malicious group deregistering a person from other groups.

public class Group { // Can have malicious subclasses.
public void deregisterPerson(Person.GroupDeregister deregister) {
if (deregister.group() != this) { // Not equals...
throw new IllegalArgumentException();
}
Person person = deregister.person();
...
}
}
public class Person { // May be subclassed.
public final class GroupDeregister {
private final Group group;
private GroupDeregister(Group group) { // Hidden.
this.group = group;
}
public Person person() {
return Person.this;
}
public Group group() {
return group;
}
}
private void groupDeregister(Group group) {
group.deregisterPerson(new GroupDeregister(group));
}
}

Another approach is to make a "public" version of Person that can be exposed to others.

public class Person { // "PrivatePerson"
public PublicPerson publicPerson() {
return new PublicPerson(this);
}
private void groupRegister(Group group) {
group.registerPerson(this);
}
private void groupDeregister(Group group) {
group.deregisterPerson(this);
}
...
}
public class PublicPerson {
private final Person person;
public PublicPerson(Person person) {
this.person = person;
}
@Override public final boolean equals(Object obj) {
return obj instanceof Person && (Person)obj.person == person;
}
@Override public final int hashCode() {
return person.hashCode();
}
...methods, but no raw registration...
}
public class Group {
private final Set<Person> members = new IdentityHashSet<>(); // No Object.equals.
public void registerPerson(Person person) {
members.add(person);
}
public void deregisterPerson(Person person) {
members.remove(person);
}
public Set<PublicPerson> members() {
// This will be more concise in Java SE 8.
Set<PublicPerson> publics = new HashSet<>();
for (Member member : members) {
publics.add(member.publicPerson());
}
return unmodifiableSet(publics);
}
}

(Objects.requireNonNull left out for "brevity".)

JS: Is there a way to tell what object called a function?

Can't you pass an ID to the Flash object when you instantiate it? (via a query string or params). Then you could use that ID in your JavaScript function calls.

Javascript: know which object function has been called

One approach could be to use a Proxy to create "tracked" objects where you intercept any method invocations:





function trackMethodCalls(obj) {

const handler = {

// anytime we do obj.someMethod

// we actually return the interceptedMethod instead

get(target, propKey, receiver) {



const method = target[propKey];


// we only do something special if we're working with a function

// on the object. If the property isn't a function we can just return

// it as normal.

if (typeof method !== 'function') {

return method;

}


return function interceptedMethod(...args) {

const result = method.apply(this, args);


console.log(

`${propKey}(${args.join(",")}) = ${JSON.stringify(result)}`

);


return result;

};

}

};

return new Proxy(obj, handler);

}


const obj = {

val: 2,

double(x) {

return this.val * x;

}

};


const trackedObj = trackMethodCalls(obj);


trackedObj.double(4);

get object on which a method was called in Python

If you never plan on reassigning math_ops outside A, this is fairly simple to do.

from modules import math_ops

class A():
def __init__():
self.math_ops = math_ops.B(self)
self.number = 1

modules/math_ops.py:

class B():
def __init__(self, creator):
self.creator = creator

def add_1():
creator.number += 1

I will mention it again in case you skimmed the first line, the following will generate unexpected results since B is tracking the creator of the object rather than the caller.

a1 = A()
a2 = A()
a1.math_ops = a2.math_ops
a1.math_ops.add_1() # a2 is updated

If that looks like something you might wanna do, the answer is a tad more complicated. Here's my attempt:

from modules import math_ops
class A():
def __init__(self):
self._math_ops = math_ops.B(self)
self.number = 1

@property
def math_ops(self):
self._math_ops.set_caller(self)
return self._math_ops

@math_ops.setter
def math_ops(self, new_math_ops):
self._math_ops = new_math_ops

modules/math_ops.py:

class B():
def __init__(self, caller):
self.caller = caller

def set_caller(self, caller):
self.caller = caller

def add_1(self):
self.caller.number += 1


Related Topics



Leave a reply



Submit