[Ironruby-core] Experimentation

John Messerly jomes at microsoft.com
Sun Oct 14 02:13:34 EDT 2007

Hi Curt,

Sounds like a method binder bug. The workaround is to merge the two methods into one:

[RubyMethod("scan", RubyMethodAttributes.PublicInstance)]
public static object Scan(CodeContext/*!*/ context, MutableString/*!*/ self, MutableString searchStr, BlockParam block) {
    if (block == null) {
        // block wasn't supplied
    } else {
        // ...

Even though a "BlockParam" argument is present, you can still call the method w/o a block. (Essentially, all "BlockParams" are [Optional])
In the meantime, I'll see if I can figure out why the binder is picking the wrong overload.

- John

From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Curt Hagenlocher
Sent: Saturday, October 13, 2007 8:16 PM
To: ironruby-core at rubyforge.org
Subject: [Ironruby-core] Experimentation

I thought I'd implement some missing members on the String class in order to get my feet wet and start to understand the software.  I chose String.scan on the grounds that it was a fairly common function (between 20 and 30 references in the standard library) with straightforward semantics, but one which requires dealing with overloads and blocks.

There are basically four variations of this function:
String.scan <string>
String.scan <regexp>
String.scan <string>, <block>
String.scan <regexp>, <block>

I've attempted to implement each of these, and believe that all but the last are correct.  The <string> variations are implemented in two different flavors for both CLR strings and mutable strings.  A patch can be found at http://hagenlocher.org/software/MutableString.scan.patch.txt

The two issues I ran into are as follows:
1) The overload mechanism is picking the wrong method at runtime.  Here are two of the function prototypes:

[RubyMethodAttribute("scan", RubyMethodAttributes.PublicInstance)]
public static List<object> Scan(MutableString/*!*/ self, MutableString/*!*/ searchStr)
[RubyMethodAttribute("scan", RubyMethodAttributes.PublicInstance)]
public static object Scan(CodeContext/*!*/ context, MutableString/*!*/ self, MutableString searchStr, BlockParam block)

When I run from rbx.exe, I get the following:
>>> "hello world".scan("l")
=> ["l", "l", "l"]
>>> "hello world".scan("l") {|x| print x}
=> ["l", "l", "l"]

In contrast, CRuby gives this:
irb(main):001:0> "hello world".scan("l")
=> ["l", "l", "l"]
irb(main):002:0> "hello world".scan("l") {|x| print x}
lll=> "hello world"

Am I doing something wrong, or is this a bug?  (I have obviously updated Initializer.Generated.cs, or neither scan would have been found :).

2) My implementation of String.scan <regexp>, <block> is incomplete.  This function is defined to behave as follows:
   a.scan(/\w+/) {|w| print "<<#{w}>> " }
   a.scan(/(.)(.)/) {|x,y| print y, x }

In other words, the number of parameters being passed to the block is equal to the number of groups defined in the regular expression -- or 1 if there are no groups defined.  I haven't been able to find way to pass parameters  or define a call site or that would support this.

Finally, it's a bit annoying to rebuild Initializer.Generated.cs.  Whenever you change a method signature, you have to manually delete the appropriate part of the old file in order to regenerate it, or you'll get an error.  I've made an empty version of that source file and a batch file that copies it on top of the previous version before rebuilding ClassInitGenerator.  Assuming that the architecture is going to be here for a while, it would be nice if there were a target in the Rakefile that performed these steps.

After a few more hours of this, I may have to figure out how to do that myself. :)

Curt Hagenlocher
curt at hagenlocher.org<mailto:curt at hagenlocher.org>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071013/e14829f7/attachment.html 

More information about the Ironruby-core mailing list