Code Review: New

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

Mostly Ruby changes and a couple of utility methods in DLR.

Fixes class instantiation, including bug
http://ironruby.codeplex.com/WorkItem/View.aspx?WorkItemId=1085.

Several cases need to be distinguished in Class#new:

  1.  The class defines or inherits an initializer ("initialize" 
    

method) that is not the default Object#initializer.

a. The initializer is a Ruby method (written in Ruby).

=> Use a default constructor to create the instance and invoke the
initializer on it. If the class derives from CLR class with no default
constructor an exception is thrown.

b. The initializer is defined in a built-in class/module.

                                                           i. 

The class being instantiated is a Ruby class (deriving from a built-in
class).

Use default constructor and invoke the initializer.

                                                         ii. 

The class is a CLR class.

Use constructor or factory. Do not call the initializer (built-ins must
initialize the object completely in constructors/factories and provide
initializers only for a direct call).

  1.  Otherwise.
    

=> Use constructor or factory. Do not call the initializer.

If the first parameter of a CLR constructor is of type RubyClass it is
considered optional and hidden (like RubyContext or RubyScope) and the
binder passes the class object that represents the class being
instantiated.

Adds support for RubyContext hidden parameter to the constructor
generator in RubyTypeBuilder. The first RubyContext or RubyClass
parameter is considered a special hidden parameter. The built type needs
to store RubyClass instance to _class field. If the base constructor
already has RubyClass the derived ctor has the same signature. If the
base constructor takes RubyContext the derived ctor takes RubyClass in
its place and passes its context to the base ctor. If the base ctor
doesn’t have RubyClass or RubyContext parameter RubyClass parameter is
injected. We also need to ensure that we don’t create duplicate
constructors (e.g. if there is a parameter-less overload, an overload
taking RubyContext and an overload taking RubyClass).

Adds unique number to the name of each lambda to avoid duplicate CLR
method names when the code saved to assembly. This removes PEVerifier
failures.

Fixes implementation of RubyOverloadResolver.GetParameterCount to count
hidden parameters correctly.

Tomas

On 12/05/2009, at 1:49 PM, Tomas M. wrote:

Several cases need to be distinguished in Class#new:

  1.  The class defines or inherits an initializer (“initialize”  
    

method) that is not the default Object#initializer.
a. The initializer is a Ruby method (written in Ruby).
=> Use a default constructor to create the instance and invoke the
initializer on it. If the class derives from CLR class with no
default constructor an exception is thrown.

I may be missing other context, but what happens if I want to do this:

public class ClrClass
{
public ClrClass(string param1) { … }
// no other constructors
}

class RubyClass < ClrClass
def initialize(param1)
super(param1) # or just super should also pass the param1 if my
memory is correct…
end
end

???

That wouldn’t work (you’ll get an exception). You need to define “new”
instead:

class RubyClass < ClrClass
def self.new (param1)
super
end
end

CLR and Ruby use different allocation schema. CLR creates objects
atomically while Ruby creates an empty/uninitialized object and then
calls initialize. You can’t use Ruby’s way on CLR objects that don’t
allow empty object allocation (don’t have default constructors).

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Orion E.
Sent: Monday, May 11, 2009 10:43 PM
To: [email protected]
Subject: Re: [Ironruby-core] Code Review: New

On 12/05/2009, at 1:49 PM, Tomas M. wrote:

Several cases need to be distinguished in Class#new:

  1.  The class defines or inherits an initializer ("initialize" 
    

method) that is not the default Object#initializer.
a. The initializer is a Ruby method (written in Ruby).
=> Use a default constructor to create the instance and invoke the
initializer on it. If the class derives from CLR class with no default
constructor an exception is thrown.

I may be missing other context, but what happens if I want to do this:

public class ClrClass
{
public ClrClass(string param1) { … }
// no other constructors
}

class RubyClass < ClrClass
def initialize(param1)
super(param1) # or just super should also pass the param1 if my
memory is correct…
end
end

???