Blogged by Ujihisa. Standard methods of programming and thoughts including Clojure, Vim, LLVM, Haskell, Ruby and Mathematics written by a Japanese programmer. github/ujihisa

Sunday, November 7, 2010

The Implementation of Enumerable#map of JRuby

See src/org/jruby/RubyEnumerable.java.

@JRubyMethod(name = {"map"}, frame = true, compat = CompatVersion.RUBY1_9)
public static IRubyObject map19(ThreadContext context, IRubyObject self, final Block block) {
    return collectCommon19(context, self, block, "map");
}

This looks like defining the map19 method with declaring it's the map method in Ruby, particularly in 1.9 mode. For some reason this is internally collectCommon19() not mapCommon19().

private static IRubyObject collectCommon19(ThreadContext context, IRubyObject self, final Block block, String methodName) {
    final Ruby runtime = context.getRuntime();
    if (block.isGiven()) {
        final RubyArray result = runtime.newArray();

        callEach19(runtime, context, self, new BlockCallback() {
            public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
                IRubyObject larg = checkArgs(runtime, largs);
                IRubyObject value = block.yield(ctx, larg);
                synchronized (result) {
                    result.append(value);
                }
                return runtime.getNil();
            }
        });
        return result;
    } else {
        return enumeratorize(runtime, self, methodName);
    }
}

This is the definition of collectCommon19. Focus on the then clause of the main if condition block. It's basically calling callEach19() with an instance of BlockCallback, redefining call(). This looks like block-passing style in Ruby.

Focus also on the line just before the callEach19(). The variable result looks like an empty Ruby array for storing values in map process. The definition of the method newArray() is the following.

public RubyArray newArray() {
    return RubyArray.newArray(this);
}

OK. How about RubyArray.newArray().

/** rb_ary_new
 *
 */
public static final RubyArray newArray(final Ruby runtime) {
    return newArray(runtime, ARRAY_DEFAULT_SIZE);
}

Ok, next. Note that the constant ARRAY_DEFAULT_SIZE is an int value.

public static final RubyArray newArray(final Ruby runtime, final int len) {
    RubyArray array = new RubyArray(runtime, len);
    RuntimeHelpers.fillNil(array.values, 0, array.values.length, runtime);
    return array;
}

Looks like [0, ..., 0] with size ARRAY_DEFAULT_SIZE. So you may wonder is it OK to define a longer array if the receiver of map has longer size than ARRAY_DEFAULT_SIZE? I also wonder.

No comments:

Post a Comment

Followers