# Code Review: MethodBinder23

**URL:** <https://www.ruby-forum.com/t/code-review-methodbinder23/148238>\
**Category:** IronRuby\
**Created:** [September 10, 2008, 8:24pm UTC](https://www.ruby-forum.com/t/code-review-methodbinder23/148238 "2008-09-10T20:24:40Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![grujildo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/94ad74/32.png) [@grujildo](https://www.ruby-forum.com/u/grujildo)\
**Post date:** [September 10, 2008, 8:24pm UTC](https://www.ruby-forum.com/t/code-review-methodbinder23/148238/1 "2008-09-10T20:24:40Z")

</div>

tfpt review “/shelveset:MethodBinder23;REDMOND\tomat”

* * *

## Ruby changes

This change significantly affects Ruby method definitions in C#  
libraries:

1. CodeContext hidden parameter is replaced with RubyScope or  
RubyContext hidden parameters depending on what the method needs.  
CodeContext is still supported but will eventually be dropped. Methods  
shouldn’t use any special parameters if they don’t need to. Methods  
should use RubyContext if they only need to get the current runtime  
context (note that you can get to the runtime context also from non-null  
BlockParam, RubyClass, RubyModule, and other runtime-bound Ruby  
objects). Currently we have 2 contexts: RubyExecutionContext and  
RubyContext. RubyExecutionContext is going to be merged into RubyContext  
soon. For now you can get it from RubyContext using ExecutionContext  
property. Methods that need to access the current scope or need to call  
a dynamic site need RubyScope. RubyScope holds on  
RubyContext/RubyExecutionContext so it is not necessary for a method to  
take both RubyScope and RubyContext parameters. In future dynamic sites  
will be passed in a special hidden parameter(s).

2. The shelveset introduces DefaultProtocol attribute that can be  
applied on parameters of type MutableString and Int32 (more types will  
be supported in future). This feature removes the need to explicitly  
call Protocols.CastToString and Protocols.CastToFixnum as the binder  
performs the conversions for you. The only method that uses the  
attribute so far is String#center. However, most of the methods that use  
CastToString/Fixnum will be switched to DefaultProtocol eventually.

3. BlockParam parameter now precedes self parameter and [NotNull]  
attribute is used for overload resolution if applied on BlockParam. A  
method that doesn’t include BlockParam can still be called with a block.  
The block is ignored in this case.

If the method overload doesn’t have a BlockParam parameter, we inject  
MissingBlockParam parameter and arg builder.  
The parameter is treated as a regular explicit mandatory parameter.

The argument builder provides no value for the actual argument  
expression, which makes the default binder to skip it  
when emitting a tree for the actual method call (this is necessary since  
the method doesn’t in fact have the parameter).

By injecting the missing block parameter we achieve that all overloads  
have either BlockParam, [NotNull]BlockParam or  
MissingBlockParam parameter. MissingBlockParam (MBP) and BlockParam (BP)  
are convertible to each other. Default binder prefers  
those overloads where no conversion needs to happen, which ensures the  
desired semantics:

Conversions with desired priority (the less number the higher priority):

Parameters: call w/o block call with non-null block  
call with null block  
(implicit, MBP, … ) MBP -\> MBP (1) BP -\> MBP (3)  
BP -\> MBP (2)  
(implicit, BP, … ) MBP -\> BP (2) BP -\> BP (2)  
BP -\> BP (1)  
(implicit, BP!, … ) N/A BP -\> BP! (1)  
N/A

1. Methods designated by RubyConstructor attribute must have RubyClass  
self parameter. The class object being instantiated is passed in it.

2. A RubyConstant attribute can now be applied on a method. The method  
is called during class initialization to produce the value of the  
constant.

Many library methods were adjusted to match the binder changes.  
Adds more checks to class-init generator to enforce correct method  
signatures.  
Also adds library data dictionary to RubyContext - libraries can add  
objects to the dictionary that should be associated with the context.

Fixes bugs in Struct:

- Struct defines a singleton method “new” that is used to create new  
structures (classes).
- If Singleton(Struct)#new method is removed, Class#new is invoked  
instead, which raises missing allocator error.
- A class created by Singleton(Struct)#new is a structure class that  
defines accessors specified in struct constructor and its singleton  
class defines “[]”, “members” and “new” methods. “new” create an  
instance of the structure given values for the struct’s attributes.
- Structures can be derived from and duplicated.

* * *

## DLR changes

Renames MethodBinderContext to ParameterBinder and removes a dependency  
on CodeContext from it. A subclass of ParameterBinder,  
ParameterBinderWithCodeContext adds CodeContext expression to  
ParameterBinder. The idea is that this class will eventually move to  
Python and become PythonParameterBinder and the default binder won’t  
depend on CodeContext. Methods on ActionBinder that deal with parameters  
could also be moved to ParameterBinder then (e.g.  
GetByRefArrayExpression, ParametersEquivalent, CanConvertFrom,  
BindSpecialArgument, PrepareArgumentBinding). These methods cannot be  
moved now since the parameter binder is not flown to all places where it  
would be needed. Adds RubyParameterBinder which implements custom  
parameter conversions for Ruby library methods.

Adds more methods to ActionBinder (should move on ParameterBinder in  
future):

- 

```
  PrepareArgumentBinding, BindSpecialArgument - used in 

```

MethodBinder when the method candidates are built up. These extension  
points enable to preprocess parameter infos and produce language  
specific ParameterWrappers and ArgBuilders and skip initial language  
specific hidden arguments. Ruby uses this to process hidden arguments of  
types RubyScope, RubyContext and CodeContext (which is deprecated and  
will be gradually removed from libraries). Also passing blocks to  
library methods are handled in a special way: Most of the library  
methods can accept a block even though they ignore it. It would be  
tedious to use the block parameter when not needed and therefore the  
Ruby binder injects it automatically to the ParameterWrappers and  
ArgBuilders if not specified. The injected parameter is of type  
MissingBlockParam and implicit conversions are defined from BlockParam  
to MissingBlockParam and vice versa. Therefore, for the purpose of  
overload resolution, each method has a block parameter. If no block is  
specified at call-site overloads with MissingBlockParam are preferred,  
followed by nullable BlockParam ([NotNull]BlockParam overloads are not  
applicable). If a block is specified but is null then nullable  
BlockParam has precedence over MissingBlockParam ([NotNull]BlockParam  
overloads are not applicable). If a block is specified and is not null  
then the order is [NotNull]BlockParam \> BlockParam \> MissingBlockParam.

- 

```
  CanConvertFrom - moved here from ParameterWrapper and changed 

```

the parameter to ParameterWrappers instead of Type. This allows to  
customize conversions based upon attributes and other modifiers applied  
on the parameters in addition to the type of the parameter.

- 

```
  ParametersEquivalent - used from ParameterWrapper to detect 

```

whether parameters are equivalent in parameter ordering used for  
overload resolution.

Adds Candidate enum with values { Equivalent, One, Two} and refactors  
various CompareTo, PreferConvert, SelectBestConversionFrom methods to  
return values of Candidate enum instead of integers.

Adds ParameterInfo property to both ParameterWrapper and ArgBuilder. The  
value is optional and some kinds of parameters and arg builders might  
not be associated with parameter-info. The purpose is to allow parameter  
comparison and conversion methods to make decisions based upon  
parameter-info properties when available.

Deletes Dynamic class. It’s not used anywhere.

Minor changes:

- 

```
  Refactored MethodTarget.MakeExpression.

```

- 

```
  Renamed PrepareArgumentBinding to PrepareParameterBinding, 

```

BindSpecialArgument to BindSpecialParameter.

- 

```
  Renamed CompareTo methods on ParameterWrapper to 

```

GetPreferredParameter(s), made them static and renamed their arguments  
so that the value of Candidate enum expresses the preference that is  
made by the method.

- 

```
  Refactored usage of nullable Candidate enum, replaced it by 

```

Candidate.Ambiguous enum value. I’ve also added extension methods for  
the enum that makes the code working with Candidate enum more readable.

- 

```
  Removed type parameter from *ArgBuilder ctors where possible, 

```

add ctor overloads for callers that pass no parameter info.

- 

```
  Removed #if BUG - I forgot that in the source code.

```

- 

```
  Added comments where missing.

```

In addition, I’ve moved classes that are related to overload resolution  
implementation in default binder from Generation into Actions.Calls  
namespace.

* * *

## Python changes

Pass parameter binder with code context to default binder instead of  
code context.

Tomas
