[Ironruby-core] Code Review: NewMethodBinder

Tomas Matousek Tomas.Matousek at microsoft.com
Tue Apr 7 14:47:19 EDT 2009

Tfpt review /shelveset:NewMethodBinder;tomat

Affects outer DLR, Python, Ruby.

DLR, Python

Redesigns the default method binder:

-          Merges ParameterBinder into MethodBinder, moves virtual methods related to CLR method binding and parameter conversions from ActionBinder and DefaultBinder to MethodBinder.

-          MethodBinder is now an abstract class that provides virtuals that languages can override. DefaultMethodBinder provides simple implementation that languages can base their binders on or directly use.

-          Enables "partially restricted splatting" feature (only implemented in Ruby so far, but should be relatively easy to generalize it and use it by default):

-          Previous implementation required languages to pass the binder an array of meta-objects including all items of the splatted array. This is not feasible for splatting arrays containing thousands of items (StackOverflow exception occurred in a Ruby library due to an expression of depth greater than 5k constructed as a rule condition). The new implementation allows the binder to only construct such conditions and restrictions that are necessary to decide which overload to select. In the worse case, which occurs e.g. when the overload set is { foo(params int[]), foo(params object[]) } and the call-site is foo(*([1]*10000 + ['x'])) , the condition that decides whether an overload/rule is applicable is implemented using a loop rather than disjunction of 10001 type equality expressions. Usually, the overload could be selected by splatting the array partially, using few items of the array from beginning and/or end of the array. More optimizations to the partial  splatting are certainly possible - those should be easy to implement on top of the new method binder architecture if needed.

-          MethodBinder builds its state in several steps (see ResolveOverload method):

1)      TargetSets and MethodCadnidates are built - MethodCandidate represents a CLR method overload tailored to a fixed arity (a follow-up refactoring will merge MethodTarget into MethodCandidate, they map 1:1). TargetSet represents a set of MethodCandidates (CanidateSet would be a better name - will rename in a follow-up change) that match the same arity. Building MethodCandidates involve creating ParameterWrappers and ArgBuilders. This process can be customized by languages. Languages can define their own wrappers and builders, their own dictionary and array splatting mechanisms.

2)      The ActualArguments class is created (this is also customizable by languages). ActualArguments instance holds on meta-objects of positional and named arguments, actual argument names, and various indices needed for splatting.

3)      TargetSet with arity corresponding to the number of actual arguments is created. If the binder implements partial splatting, the array is splatted to match arities of existing target sets but no more. The rest of the arguments (those that were not extracted from the array) are referred to as "collapsed" and are dealt with separately during overload resolution. The previous implementation of "MakeBindingTarget" is replaced by a new one, which fixes issues with named arguments and also takes collapsed arguments into consideration. It has several steps:

a.       Match actual names of the arguments with parameter names, calculate permutations that map indices of the former to the latter, and filter out MethodCandidates whose parameter names don't match. The result of this step is a set of ApplicableCandidates, each ApplicableCandidate comprises of a MethodCandidate and a ArgumentBinding permutation.

b.      Then for each narrowing level: Non-collapsed arguments are tested for convertibility to the parameter types of the applicable overloads. Those overloads that don't match are removed from applicable candidates set. If no overloads remain, it's an error. If a single overload remains we successfully chosen the overload (note that collapsed arguments don't need to be visited in this case). Otherwise we check whether collapsed arguments can all be converted to the element type of the corresponding params-array. Again, if no candidate remains, we failed. If a single one remains we succeeded. Otherwise we continue by comparing various conversions and selecting the best ones based on the current narrowing level.

-          During these steps the MethodBinder builds its state (candidate sets, actual arguments, etc.) and derived method binders can also remember some additional data/state that is used for building arguments or error reporting (temporary variable that stores the splattee, restrictions/conditions used for splatting, the signature of the call-site, etc.). The MethodBinder should be instantiated with all information that doesn't change during overload resolution (the "input" to the overload resolution).

-          Renames ParameterBinderWithCodeContext to PythonMethodBinder and moves it to Python.

-          Moves SiteLocalStorage to Python. Ruby uses a different storage class and it's very simple for languages to define and use their own.

-          ActionBinder.BindSpecialParameter shouldn't deal with CodeContext and SiteLocalStorage - moved to PythonMethodBinder.

-          Moved ContextArgBuilder and SiteLocalStorageArgbuilder to Python.

-          ArgBuilder.CanGenerateDelegate needs to be protected so that custom ArgBuilders can override it.

-          Improves errors reported by the method binder.

-          Removes old call, invoke  and operation actions and related code.


-          Replaces calls to obsolete methods of default method binder with those using meta-objects.

-          Implements partially restricted splatting.

Fixes http://ironpython.codeplex.com/WorkItem/View.aspx?WorkItemId=18379.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20090407/d4e890b5/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: NewMethodBinder.diff
Type: application/octet-stream
Size: 195886 bytes
Desc: NewMethodBinder.diff
URL: <http://rubyforge.org/pipermail/ironruby-core/attachments/20090407/d4e890b5/attachment-0001.obj>

More information about the Ironruby-core mailing list