Ah, the semantics do make sense now. In that case, perhaps there's one more solution:
class PersonShim < Example1::Person def self.new(first, last) Example1::Person.new(first, last) end end class Person2 < PersonShim def initialize(first, last) super(first, last) end end Person2.new(""Foo"", ""Bar"") In my case, I need to make sure that the C# types that I expose to IronRuby behave almost identically to what you would expect with a pure Ruby implementation. If you remember back when I was talking about my game engine clone, I need to make sure that I don't break user's scripts - so I need to preserve the "expected" semantics of `initialize`. What I could do is end my C# classes with "Impl", and write a corresponding Ruby class that invokes the correct constructor in `new` (ex: SpriteSubclass -> Sprite -> SpriteImpl). Mind giving me a sanity check on this, Tomas? I think this should fix the problem I was having with subclassing my Sprite class - which get's me one step closer to releasing this beast! Thank you, Tomas, that was a very thorough explanation. -Charles On Fri, Sep 24, 2010 at 2:38 AM, Tomas Matousek < tomas.matou...@microsoft.com> wrote: > This behavior is actually by design. > > > > The error message says: “… define Person2#new singleton method instead of > Person2#initialize” like so: > > > > class Person2 < Example1::Person > > def self.new(first, last) > > super(first, last) > > end > > end > > > > person = Person2.new("Foo", "Bar") > > p person.first_name, person.last_name > > > > We do pick up the superclass’s constructors if you don’t specify no > initialize method, so this works too: > > > > class Person2 < Person > > end > > > > person = Person2.new("Foo", "Bar") > > p person.first_name, person.last_name > > > > The reason why this doesn’t work when you define initialize is to make you > aware of the fact that your initialize method doesn’t do what you might > expect, that is it doesn’t call the constructor of the superclass. > > > > If you define a default ctor in the superclass and you have initialize > method in the subclass, the constructor gets invoked to create the object > and initialize is called to initialize it. This patter is kind of close to > Ruby semantics. > > > > So you basically have 3 options: > > - Do not define new nor initialize => the ctors from base class > are available for construction of the subclass > > - Define singleton new => you can choose which base ctor is > called. > > - The base class has a default ctor and the subclass defines > initialize method => the default ctor is always used for object construction > and the initialize is called with the arguments given to “new”. > > > > The reason why we chose this design is due to difference between Ruby and > CLR initialization semantics. CLR classes don’t separate allocation > (“allocate”) from initialization (“initialize”) like Ruby does. CLR has just > constructors (which kind of corresponds to Ruby factory method “new”). > Constructors combine allocation and initialization. The problem with mapping > initialize to CLR constructors is that it operates on “self” that is already > allocated before you can do anything (like call super): > > > > def initialize(first, last) > > p self.first_name # self is already an instance of > Person2 here, so we must have called some constructor already (the default > one if available) > > super(first, last) # what should this do? We can’t > call the constructor again… it’s too late. > > end > > > > > > As for what super(first, last) does in your code … it calls > “Object#initialize”, which in Ruby 1.9.2 has *args parameters and does > nothing: > > > > >>> class X; end > > => nil > > >>> init = X.instance_method(:initialize) > > => #<UnboundMethod: X(Object)#initialize> > > >>> init.parameters > > => [[:rest]] > > >>> X.new.send(:initialize, 1,2,3,4,5) > > => #<X:0x0000056> > > > > Tomas > > > > *From:* ironruby-core-boun...@rubyforge.org [mailto: > ironruby-core-boun...@rubyforge.org] *On Behalf Of *Charles Strahan > *Sent:* Thursday, September 23, 2010 11:40 PM > *To:* ironruby-core@rubyforge.org > *Subject:* [Ironruby-core] Inheritance in IronRuby - possibly a bug or > two? > > > > I have a couple questions about deriving from C# class from IronRuby. For > context, here's a code example that I will refer to here in a bit: > > > > ======================================== > > > > using System; > > using System.Reflection; > > using IronRuby; > > using IronRuby.Runtime; > > using Microsoft.Scripting.Hosting.Providers; > > > > namespace Example1 > > { > > public class Person > > { > > public string FirstName { get; set; } > > public string LastName { get; set; } > > > > public Person(string firstName, string lastName) > > { > > FirstName = firstName; > > LastName = lastName; > > } > > } > > > > class Program > > { > > private static readonly string _rubyScript = @" > > > > class Person2 < Example1::Person > > def initialize(first, last) > > super(first, last) > > end > > end > > > > Person2.new(""Foo"", ""Bar"") > > > > "; > > > > static void Main(string[] args) > > { > > var runtime = Ruby.CreateRuntime(); > > var engine = runtime.GetEngine("rb"); > > var context = > (RubyContext)HostingHelpers.GetLanguageContext(engine); > > var scope = engine.CreateScope(); > > runtime.LoadAssembly(typeof(Program).Assembly); > > > > engine.Execute(_rubyScript, scope); > > > > Console.WriteLine(". . ."); > > Console.ReadKey(true); > > } > > } > > } > > > > > > ======================================== > > > > > > If you run that code, you'll get the following: > > > > InvalidOperationException: can't allocate class `Person2' that derives from > type `Example1::Person' with no default constructor; define Person2#new > singleton method instead of Person2#initialize > > > > Is this a bug, or is this intended behavior? If this is intentional, then > I think there's still a different problem: try adding this default > constructor and then run the code: > > > > public Person() > > { > > Console.WriteLine("Uhmmm... what did IronRuby do with > `super(first, last)`?"); > > } > > > > So, the `super(first, last)` still get's executed... but what did it do? It > obviously didn't forward those arguments to the non-default constructor... > > > > So, I think that means we have one, or possibly two, bugs. > > > > Back to the first question: Wouldn't it be possible to determine the > correct constructor to invoke based on the arguments, thus avoiding the > exception? I would imagine that the generated/emitted subclass could contain > all of the same constructors that the base type has, just passing the > arguments on to the base class's corresponding constructor (I hope that made > sense - sorta tricky to word that correctly). > > > > > > By the way, how should I specify that I _don't_ want the Ruby code to be > interpreted? I noticed that the debugger broke > in Microsoft.Scripting.Interpreter.Interpreter... maybe that could be part > of the problem. > > > > Cheers, > > -Charles > > _______________________________________________ > Ironruby-core mailing list > Ironruby-core@rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core > >
_______________________________________________ Ironruby-core mailing list Ironruby-core@rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core