[Ironruby-core] Experimentation

Curt Hagenlocher curt at hagenlocher.org
Sun Oct 14 09:52:02 EDT 2007


Thanks for all of the excellent advice; everything is now working.  I had
guessed there might be an issue on the overload with the specific signature
of the function, but I wasn't able to find any examples of existing code
that contradicted what I had done.  Now that I know what to look for, of
course... :).  I wonder if it wouldn't be a good idea for the
ClassInitGenerator to emit a warning when there's a signature containing a
BlockParam that doesn't follow the correct pattern.

The /*!*/ annotation seems a bit redundant with [NotNull], doesn't it? I
think I'm just resentful that it's a bunch of characters that totally
interrupt the flow of my typing. :P

I considered merging the block form of the scan function with the blockless
form, but it seemed that the result would be considerably harder to read and
understand than keeping them seperate.

Is this the sort of change you'd like to see submitted to the project?  If
so, I'll write some tests (I know; should have done it the other way around)
and generate another patch file.

On 10/13/07, Tomas Matousek <Tomas.Matousek at microsoft.com> wrote:
>
>  1)      Change the signatures to:
>
>         [RubyMethodAttribute("scan", RubyMethodAttributes.PublicInstance)]
>
>         public static List<object>/*!*/ Scan(MutableString/*!*/ self, [
> NotNull]MutableString/*!*/ searchStr)
>
>
>
>         [RubyMethodAttribute("scan", RubyMethodAttributes.PublicInstance)]
>
>         public static object Scan(CodeContext/*!*/ context, MutableString
> /*!*/ self, [NotNull]BlockParam/*!*/ block, [NotNull]MutableString/*!*/searchStr)
>
>
>
> a)      Block is a special parameter and it must follow self parameter.
> The order of parameters is:
>
> ·         context
>
> ·         self
>
> ·         block
>
> ·         mandatory parameters
>
> ·         optional parameters
>
> ·         params array (rest parameters)
>
> b)      Specify [NotNull] for parameters that cannot be null in order to
> select the overload. You can assume that parameters doesn't have null value
> when called from a DLR language. It's not a CLR attribute though so it
> doesn't prevent a non-dynamic languages to pass null. Since the library
> methods are not supposed to be called directly (only Ruby runtime should
> invoke the method), you don't need to check for non-nullity at runtime.
> Context parameter is always non-null (no need to check for null at
> run-time). Self parameter is also non-null unless the method is a module
> method or an instance method of NilClass.
>
> c)       Annotate types by /*!*/ annotation if you assume them to be
> non-null. Although the annotation doesn't affect run-time behavior at all
> (being a comment, it's ignored by C#) it is useful for static analysis and
> expresses your assumptions.
>
> d)      Note also that unless marked by NotNull attribute, BlockParam is
> nullable. Hence the overload might be eligible for invocation even though no
> block has been passed. A null reference is used if the block is not
> specified in a call site and there is no overload that matches better. So a
> single overload with BlockParam parameter also works. It depends on the
> semantics of the method which variant to chose. If presence of the block
> significantly changes the behavior of the method then it's probably better
> to have two overloads. Code like [RubyMethod("foo")]public static Foo(…
> block …) { if (block != null) { 1st overload implementation } else { 2ndoverload implementation} } should be avoided if possible; two overloads
> should be defined instead. On the other hand, if the implementation almost
> doesn't depend on whether the block is present or not (it only affects a
> small part of the implementation) then it's probably better to have a single
> overload.
>
>
>
> 2)      Check out dynamic site in Thread.CreateThread. It should do what
> you need. The magic is in ArgumentKind.List (splat).
>
> 3)      Feel free to patch the Rakefile. Note however, that we are going
> to change the shape of libraries a little bit (in particular move Builtins
> to IronRuby.Libraries.dll), so it might be necessary to adjust the script
> again afterwards.
>
>
>
> Note that MutableString has an instance method IndexOf, so you don't need
> to convert to a CLR string (the method internally makes the conversion but
> that's only provisional implementation).
>
>
>
> Tomas
>
>
>
> *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
>
> _______________________________________________
> Ironruby-core mailing list
> Ironruby-core at rubyforge.org
> http://rubyforge.org/mailman/listinfo/ironruby-core
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071014/29b798bd/attachment.html 


More information about the Ironruby-core mailing list