# Code Review: EMS10

**URL:** <https://www.ruby-forum.com/t/code-review-ems10/190876>\
**Category:** IronRuby\
**Created:** [June 29, 2010, 5:48pm UTC](https://www.ruby-forum.com/t/code-review-ems10/190876 "2010-06-29T17:48:57Z")\
**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:** [June 29, 2010, 5:48pm UTC](https://www.ruby-forum.com/t/code-review-ems10/190876/1 "2010-06-29T17:48:57Z")

</div>

tfpt review “/shelveset:EMS10;REDMOND\tomat”  
Comment :  
Implements support for extension methods in IronRuby.

DLR:

- Factors out reusable parts of type inferer to ReflectionUtils and  
simplifies the inferer a bit. We need to bind generic parameters when  
dealing with extension methods whose first parameter is an open  
constructed type.
- Moves around a few methods in ReflectionUtils so they are better  
organized to regions.
- Implements extension method reflection services in ReflectionUtils.  
The implementation will improve when we’ll get our new metadata reader  
checked-in. We’ll also need a slightly different extension method  
enumeration scheme for Python. I’ll also rename ReflectionUtils to  
ReflectionServices when they use the new metadata reader and move it out  
of Utils directory. They are becoming more than just simple utils.
- Updates OverloadResolver to prefer non-extension methods over  
extension methods if it can’t decide which overload is better based on  
other criteria.
- Implements a workaround for a bug in MethodInfo.GetBaseMethod in  
CompilerHelpers.TryGetCallableMethod. The API might return a generic  
method definition even if called on a method instantiation.
- Small improvements to a couple of ArrayUtils.

Ruby:

- Adds method Kernel#using\_clr\_extensions that takes a namespace and  
activates all extension methods defined on classes defined in that  
namespace (doesn’t include sub-namespaces) regardless of the assembly  
they are defined in. All assemblies already loaded to the current  
ScriptRuntime are reflected for extension methods and any assembly that  
is loaded in the future gets reflected as well. This means that  
additional extension methods might appear when a new assembly is loaded.  
For each affected type the loaded extension methods are added to the  
overload sets of existing methods (if there are any). Thus if class C  
defines an instance method foo() and an extension method foo(this C,  
int) is loaded the next call of foo on an instance of C will trigger  
overload resolution algorithm to choose among overloads { foo() and  
foo(int) }. If the resolver can’t chose based upon the call-site  
arguments the non-extension methods are preferred.
- Generic extension methods might be defined, for example like so:

public static void Foo\<S, T\>(this Dictionary\<S, T\> x, T y) where S : T  
{ }

This defined Foo on all Dictionaries whose key type is the same or  
derives from the type of the values stored in the dictionary. This is  
supported to the extent that all involved constraints can be  
instantiated using the type of the first argument to the call-site. We  
do ignore constraints that can’t. For example:

public static void Foo\<S, T\>(this S x, T y) where S : T { }

In this case the methods will be available on all types in the system.  
However if the method is invoked with an argument that is not compatible  
with the constraint the overload can’t be selected and the method call  
might fail.

If the first parameter of an extension method is not a constructed  
type (i.e. it is a plain generic parameter like in the example above)  
the method is supposed to be defined on every type in the system that  
satisfies the constrains of the generic parameter. In the current  
implementation IronRuby considers such method (say Foo) defined on  
Object and available to all applicable types via inheritance. Thus a  
Ruby method Foo or foo defined on some class A \<: Object hides the  
extension method Foo. This means that the extension method won’t be  
available from any subclass of A until the Ruby method on A gets  
removed. Ideally the extension method should appear to be defined  
directly on every type instead of just Object. However this brings  
additional complexity to the current IronRuby type system. Since  
defining an extension method on every single type is rather a corner  
case I’ve decided for the simple approach.

- We intentionally don’t enable extension methods on built-in types  
(such as Array or Hash) for two reasons:  
o There is high potential for name conflicts. For example,  
IEnumerable LINQ extensions include methods like First, Zip, Count,  
Max, Min, Sum, etc. some of these are already methods on Ruby’s  
Enumerable and other might easily be in future. We could use the policy  
of non-mangling names so that they could be called only using their CLR  
name and not the Ruby equivalent (Zip vs zip). However, then writing  
LINQ queries that work for all data sources would require to always use  
CLR names otherwise it wouldn’t work for builtins.  
o Built-ins hide CLR interface they implement to be fully compatible  
with Ruby built-ins. For example, although Array implements  
IList Array.included\_mixins == [Enumerable]. Thus it would need  
a bit of magical behavior to make the extension methods appear on Array.  
It would actually be much cleaner if a separate non-built-in class was  
defined that wraps Ruby array and implements IEnumerable. Then any  
time you want to use an array as LINQ data source you just wrap it into  
this enumerable implementation.

- An example of using LINQ extension methods:

load\_assembly “System.Core”  
using\_clr\_extensions System::Linq

p System::String.to\_clr\_type.get\_methods.  
where(System::Func[Object, System::Boolean].new { |m| m.name[0, 2]  
== ‘To’ }).  
select(System::Func[Object, Object].new { |m| m.name }).  
to\_a

# =\> [‘ToCharArray’, ‘ToCharArray’, ‘ToLower’, ‘ToLower’,

‘ToLowerInvariant’, ‘ToUpper’, ‘ToUpper’, ‘ToUpperInvariant’,  
‘ToString’, ‘ToString’]

Currently IronRuby’s type inference doesn’t infer the generic  
parameters of Where and Select methods so we need to help it by  
specifying the types explicitly.

- Fixes name mangling of “or” word.
- Fixes cross-runtime class hierarchy locking bug in constant  
resolution. It is no longer allowed to open a foreign module or class  
via module/class keyword.

Tomas
