From: Michael Neumann Date: 2007-09-23T22:09:57+09:00 Subject: Re: [ANN] CplusRuby - Gluing C and Ruby Joel VanderWerf schrieb: > > One comment on inheritance in cplusruby: > > def self.inherited(klass) > # inherit properties and c_methods > self.properties.each {|k,v| klass.properties[k] = v} > CplusRuby.registered_classes << klass > end > > Re-opening a parent class after a child class has been defined and > adding more properties will not propagate them to the child. And you > can't simply add such properties to the end of the parent and child > struct definitions, since that will make them incompatible (in the > sense of casting). Ah thanks. Well, I should definitively refactor cplusruby a bit :). A quick C question about casting: struct A { int a; } struct B { int a; int b; } Is it always safe (even with -O3) to cast a pointer of B to A? Or do I have to do: struct B { A x; int b; } which is very ugly IMHO. Are there pramgas like "__packed" for this? > Michael Neumann wrote: >> In the example you give I only see one minor difference. In CplusRuby, >> method :stimulate can be called directly from the C-side, without >> NUM2DBL conversions of Ruby-types. That's very important for my >> usage scenario. >> But I think you can do the same with cgen. > > Actually, I don't think cgen has that feature.... one of the things I'll > have to er, borrow, from cplusruby. Currently the only way to do this is > to define a separate C function that the method calls. > > Reading the cplusruby .c output, it looks like there is an outer > function (Neuron_call__stimulate) that accepts ruby value arguments, and > then converts them and calls an inner function (Neuron__stimulate), > which expects C-typed arguments. You could do this in cgen by using > define_c_method to define the outer function and define_c_function to > define the inner function. > > I guess I was used to performing the conversion manually, so I never > added that feature as a convenience. I can see that it would be more of > a necessity than a convenience if the function needed to be called from > C as well as ruby. > > The selfc->stimulate function pointer is another difference, and > necessary for the same reason, I guess. In a cshadow struct, this struct > member doesn't exist, but there is reference ("VALUE self;") back to the > original object, on which you can call methods (with the additional > friction of type conversions, if the caller is native C code). The "VALUE self" in the C structure is a feature I will borrow. It's a great idea! > The fact that you have pointers to functions that accept C-typed args > makes access from C easy and efficient, but it also uses a lot of space > in the struct with a pointer to each function that implements a method. > What about having a unique struct for each class that keeps these > pointers, and then the struct only needs a pointer to this "singleton"? I plan to make methods by default "non-virtual" in the C++ sense. That is, they will by default not be included as function pointers in the struct. If you want to have virtual methods, you'd then need to add: property :a_virtual_method, :virtual_method I also plan to support templates, which is a feature I really need for some data types like priority queues (I noticed that using templates they are a lot faster than a generic version): class ImplicitBinaryHeap include CplusRuby::Template property :size, :int property :capacity, :int property :elements, "%ELEMENT_TYPE%*" method :initialize do arguments [:initial_capacity, :int] body %{ @capacity = initial_capacity; @size = 0; @elements = ALLOC_N(%ELEMENT_TYPE%, @capacity+1); } end method :push do arguments [:element, "%ELEMENT_TYPE%*"] body %{ @size += 1; if (@size > @capacity) $resize(self, 2*@capacity + 1); @elements[@size] = *element; $propagate_up(self, @size); } end #... end MyPQ = ImplicitBinaryHeap.bind(:ELEMENT_TYPE => 'int) # now MyPQ is similar ImplicitBinaryHeap self is now a pointer to a C struct (thanks to the "VALUE self" reference). "@" is replaced by "self->", and $ is replaced by "classname__", so that you don't have to hardcode the prefix of methods (only works for non-virtual methods of course). The good thing is, that you can use the structure without associating it to a Ruby object (so you get a poor mans or not so poor mans "C with classes"): MyPQ mypq; MyPQ__initialize(&mypq, 31); for (int i = 0; i<10; i++) { MyPQ__push(&mypq, &i); } It's not that nice as the equivalent in C++, but it doesn't need a C++ compiler at all. Regards, Michael