<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=us-ascii">
<meta name=Generator content="Microsoft Word 12 (filtered medium)">
<style>
<!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
p
        {mso-style-priority:99;
        margin:0in;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";}
p.msochpdefault, li.msochpdefault, div.msochpdefault
        {mso-style-name:msochpdefault;
        mso-style-priority:99;
        margin:0in;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Times New Roman","serif";}
span.emailstyle18
        {mso-style-name:emailstyle18;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
span.EmailStyle20
        {mso-style-type:personal-reply;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page Section1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.Section1
        {page:Section1;}
-->
</style>
<!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang=EN-GB link=blue vlink=purple>
<div class=Section1>
<div style='mso-element:para-border-div;border:none;border-bottom:double windowtext 2.25pt;
padding:0in 0in 1.0pt 0in'>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>OK, so I think that this is a
problem with the AST to code generation, though I really don’t understand
it deeply enough to say exactly where.<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>If you dump the ASTs from the
ruby code the body of the loop looks like this:<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> <span
style='background:yellow;mso-highlight:yellow'>(.bound i) = (Object)0;</span><o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> .return .comma {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
.try {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
(.bound #rfc).InLoop = (Boolean)True;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
(.bound #skip-condition) = (Boolean)False;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
.for (; ; ) {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
.try {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
.if ((.bound #skip-condition) )
{(Void)(.bound #skip-condition) = (Boolean)False;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
} .else {<span style='background:yellow;mso-highlight:yellow'>.if (.action
(Boolean) ConvertTo System.Boolean( // ConvertTo to System.Boolean<o:p></o:p></span></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D;background:yellow;mso-highlight:yellow'>
.action (Object) InvokeMember <( // InvokeMember <(Instance, Simple)
ReturnNonCallable, IsCallWithThis<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D;background:yellow;mso-highlight:yellow'>
(.bound i)<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D;background:yellow;mso-highlight:yellow'>
1000<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D;background:yellow;mso-highlight:yellow'>
)</span><span style='font-size:8.0pt;font-family:"Courier New";color:#1F497D'><o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
) ) {/*empty*/;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
} .else {.break;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
<span style='background:yellow;mso-highlight:yellow'>(.bound i) =
(Object).action (Object) InvokeMember +( // InvokeMember +(Instance, Simple)
ReturnNonCallable, IsCallWithThis<o:p></o:p></span></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D;background:yellow;mso-highlight:yellow'>
(.bound i)<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D;background:yellow;mso-highlight:yellow'>
1<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D;background:yellow;mso-highlight:yellow'>
);</span><span style='font-size:8.0pt;font-family:"Courier New";color:#1F497D'><o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
} .catch ( BlockUnwinder #unwinder) {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
(.bound #skip-condition) = (.bound #unwinder).IsRedo;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
} .catch ( EvalUnwinder #unwinder) {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
.if (((.bound #unwinder).Reason == (BlockReturnReason)Break) ) {{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
(.bound #loop-result) = (.bound #unwinder).ReturnValue;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
.break;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> }
.else {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
.throw ()<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
} .finally {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
(.bound #rfc).InLoop = (Boolean)False;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
(.bound #loop-result)<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> }<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> ;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>No mention of ConvertToInt32
there although it is noticeable that the (.bound i) value is an object and not
a Fixnum.<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>If you dump the generated
code you get the following two methods for invoking the Fixnum methods:<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>public static object
$Ruby.Builtins.FixnumOps.LessThan(object[] objArray1, DynamicSite<object,
int, object> site1, CodeContext context1, object obj1, int num1)<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> if (((obj1 != null)
&& (obj1.GetType() == typeof(int))) && (((RubyClass)
objArray1[0]).get_Version() == 0x3b3e))<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
bool flag;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
bool flag1 = flag = <span style='background:yellow;mso-highlight:yellow'>FixnumOps.LessThan(Converter.ConvertToInt32(obj1),
num1)</span>;<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
return RuntimeHelpers.BooleanToObject(flag);<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> }<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> return
site1.UpdateBindingAndInvoke(context1, obj1, num1);<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>public static object
$Ruby.Builtins.FixnumOps.Add(object[] objArray1, DynamicSite<object, int,
object> site1, CodeContext context1, object obj1, int num1)<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>{<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> if (((obj1 != null)
&& (obj1.GetType() == typeof(int))) && (((RubyClass)
objArray1[0]).get_Version() == 0x3b3e))<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> {<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>
return <span style='background:yellow;mso-highlight:yellow'>FixnumOps.Add((int)
obj1, num1);</span><o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> }<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'> return
site1.UpdateBindingAndInvoke(context1, obj1, num1);<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:8.0pt;
font-family:"Courier New";color:#1F497D'>}<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>Here as Wayne points out the
code generator has added in the ConvertToInt32 in the LessThan invocation,
whereas in the Add invocation it has used a direct cast. Somewhere in the
innards of Ruby.dll this decision is being made and I haven’t tracked
down where.<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>Clearly it is not necessary
to use the conversion method: for a start there is a clause around the call to
the method that tests whether obj1 (self) is an int.<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>As it happens I am generally
doubtful about the inclusion of automated Conversion in IronRuby at all, apart
from perhaps for .NET classes that don’t map directly to Ruby ones, such
as byte and float. The design of the Ruby builtin classes manages the
conversions directly, using such things as to_s, to_str, to_f, to_int and
to_i. Getting the DLR to do hidden conversions seems to be overkill and
can upset the semantics of the library classes.<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'>Pete<o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'> <o:p></o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
<p class=MsoNormal style='border:none;padding:0in'><span style='font-size:11.0pt;
font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p>
</div>
<div>
<div>
<p class=MsoNormal><b><span lang=EN-US style='font-size:10.0pt;font-family:
"Tahoma","sans-serif";color:#1F497D'><o:p> </o:p></span></b></p>
<p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";
color:#1F497D'>Without looking at the code I can’t comment on the main
thrust of the mail, but shouldn’t the local variable i be a Fixnum from
the word go and therefore call the LessThan(int, int) method anyway?</span><o:p></o:p></p>
<p class=MsoNormal> <o:p></o:p></p>
<p class=MsoNormal><span style='color:black'>Yes, LessThan(int, int) is called
each time, but an unnecessary call is also made to method ConvertToInt32 every
time around the loop to convert what is already an integer into an integer.</span><o:p></o:p></p>
<p class=MsoNormal> <o:p></o:p></p>
<p class=MsoNormal><span style='color:black'>Cheers, Wayne.</span><o:p></o:p></p>
</div>
</div>
</div>
</body>
</html>