nosewheelie

Technology, mountain biking, politics & music.

Archive for the ‘metaprogramming’ tag

Pimp my (Java) methods

with 7 comments

A friend of mine has been playing around with Scala and asked about its meta-programming ability. In particular, he’s a Ruby fiend, so is used to its nice reflection abilities. Specifically he wanted to be able to explore an API interactively from the console, like the following for an integer in Ruby:

>> 1.class
=> Fixnum
>> 1.methods
=> ["%", "inspect", "<<", "singleton_method_added", "&", "clone", ">>", "method", "round", "public_methods", "instance_variable_defined?", "divmod", "equal?", "freeze", "integer?", "chr", "*", "+", "to_i", "methods", "respond_to?", "-", "upto", "between?", "prec", "truncate", "/", "dup", "instance_variables", "__id__", "modulo", "object_id", "succ", "|", "eql?", "zero?", "require", "~", "id", "to_f", "singleton_methods", "send", "prec_i", "taint", "step", "to_int", "frozen?", "instance_variable_get", "__send__", "^", "instance_of?", "remainder", "to_a", "+@", "nonzero?", "-@", "type", "**", "floor", "<", "protected_methods", "<=>", "instance_eval", "==", "prec_f", "quo", ">", "display", "===", "downto", "id2name", "size", "instance_variable_set", "kind_of?", "abs", "extend", ">=", "next", "to_s", "<=", "coerce", "hash", "ceil", "class", "tainted?", "=~", "private_methods", "gem", "div", "nil?", "untaint", "times", "to_sym", "[]", "is_a?"]
>> Fixnum.methods
=> ["inspect", "private_class_method", "const_missing", "clone", "method", "public_methods", "public_instance_methods", "instance_variable_defined?", "method_defined?", "superclass", "equal?", "freeze", "included_modules", "const_get", "methods", "respond_to?", "module_eval", "class_variables", "dup", "protected_instance_methods", "instance_variables", "public_method_defined?", "__id__", "object_id", "eql?", "const_set", "require", "id", "singleton_methods", "send", "class_eval", "taint", "frozen?", "instance_variable_get", "include?", "private_instance_methods", "__send__", "instance_of?", "private_method_defined?", "to_a", "name", "autoload", "type", "<", "protected_methods", "instance_eval", "<=>", "==", ">", "display", "===", "instance_method", "instance_variable_set", "kind_of?", "extend", "protected_method_defined?", "const_defined?", ">=", "ancestors", "to_s", "<=", "public_class_method", "allocate", "hash", "class", "instance_methods", "tainted?", "=~", "private_methods", "gem", "class_variable_defined?", "induced_from", "nil?", "untaint", "constants", "autoload?", "is_a?"]

Unfortunately Scala’s meta-programming abilities are currently limited to Java’s, which is to say not very good. As I’m in Rails-land at the moment, I asked Tony to have a crack at it, to which, he’s obliged:

class Classs[T](c: Class[T]) {
  lazy val methods = scala.collection.immutable.HashSet(c.getDeclaredMethods: _*) ++ c.getMethods
}

object Classs {
  implicit def c[T](c: Class[T]) = new Classs(c)
}

Here’s how to use it, we ask for all of Integer’s methods that start with a “t”:

scala> classOf[Integer].methods.filter(_.getName.startsWith("t")).foreach(println(_))
public static java.lang.String java.lang.Integer.toBinaryString(int)
public static java.lang.String java.lang.Integer.toHexString(int)
public static java.lang.String java.lang.Integer.toOctalString(int)
public java.lang.String java.lang.Integer.toString()
public static java.lang.String java.lang.Integer.toString(int,int)
public static java.lang.String java.lang.Integer.toString(int)
private static java.lang.String java.lang.Integer.toUnsignedString(int,int)

Tony’s original source: http://fprogramming.org/paste/viewpaste.php?id=107.

Written by Tom Adams

April 21st, 2008 at 12:40 pm