WeakRef implementation for JRuby

  • Thread starter Charles Oliver Nutter
  • Start date
C

Charles Oliver Nutter

Since this came up a few times, here's an example of implementing
WeakRef in JRuby, using Java code. Obviously most of the heavy lifting
is done by Java's WeakReference implementation.

I post this because I'm interested in hearing how this could be made
easier. In my eyes, this is pretty clean, and far simpler to create a
JRuby extension than a equivalent C extension...but I'm a Java guy. I'd
love to know how this can be improved. Thoughts?

<<JAVA_CODE

//// All Ruby objects extend RubyObject in JRuby right now. That may
change in the future to support objects in other branches of the class
hierarchy.

public class WeakRef extends RubyObject {

//// The Java WeakReference object, pointing at a ruby object

private WeakReference<IRubyObject> ref;

//// JRuby likes to have an allocator defined for all objects that have
their own custom Java types. Here, we create an allocator for WeakRef

private static final ObjectAllocator WEAKREF_ALLOCATOR = new
ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new WeakRef(runtime, klazz);
}
};

//// A requireable library must just implement Library. Here, we provide
a static inner class to do that...then it's trivial to wire this up as
an extension.
//// Note also this defines the WeakRef class as extending Delegator,
and defines an Exception type for RefError.

public static class WeakRefLibrary implements Library {
public void load(Ruby runtime) throws IOException {
RubyKernel.require(runtime.getKernel(),
runtime.newString("delegate"), Block.NULL_BLOCK);

RubyClass delegatorClass =
(RubyClass)runtime.getClassFromPath("Delegator");
RubyClass weakrefClass = runtime.defineClass("WeakRef",
delegatorClass, WEAKREF_ALLOCATOR);

weakrefClass.defineAnnotatedMethods(WeakRef.class);

RubyClass referrorClass = runtime.defineClass("RefError",
runtime.getStandardError(), runtime.getStandardError().getAllocator());
}
}

//// Standard constructor, pass in the JRuby runtime and the Ruby class
this object has as its metaclass.

public WeakRef(Ruby runtime, RubyClass klazz) {
super(runtime, klazz);
}

//// Here's the JRuby annotation for binding a method. This makes the
Java method "getobj" bind to WeakRef as WeakRef#__getobj__

@JRubyMethod(name = "__getobj__")
public IRubyObject getobj() {
IRubyObject obj = ref.get();

if (obj == null) {
// FIXME weakref.rb also does caller(2) here for the backtrace
throw newRefError("Illegal Reference - probably recycled");
}

return obj;
}

//// Another such binding for WeakRef::new.

@JRubyMethod(name = "new", required = 1, meta = true)
public static IRubyObject newInstance(IRubyObject clazz,
IRubyObject arg) {
WeakRef weakRef = (WeakRef)((RubyClass)clazz).allocate();

weakRef.callInit(new IRubyObject[] {arg}, Block.NULL_BLOCK);

return weakRef;
}

//// And for WeakRef#initialize. Notice that it dispatches to the
"super" implementation of initialize, which will call Delegator#initialize

@JRubyMethod(name = "initialize", required = 1, frame = true,
visibility = Visibility.PRIVATE)
public IRubyObject initialize(IRubyObject obj) {
ref = new WeakReference<IRubyObject>(obj);

return callSuper(getRuntime().getCurrentContext(), new
IRubyObject[] {obj}, Block.NULL_BLOCK);
}

//// A binding for the weakref_alive? method

@JRubyMethod(name = "weakref_alive?")
public IRubyObject weakref_alive_p() {
return ref.get() != null ? getRuntime().getTrue() :
getRuntime().getFalse();
}

//// And a utility method for constructing throwable RefError instances

private RaiseException newRefError(String message) {
RubyException exception =

(RubyException)getRuntime().getClass("RefError").newInstance(
new IRubyObject[] {getRuntime().newString(message)},
Block.NULL_BLOCK);

return new RaiseException(exception);
}
}

JAVA_CODE

- Charlie
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,078
Latest member
MakersCBDBlood

Latest Threads

Top