Strange behavior in derived class
-
Here is a set of commands in the SU Ruby console:
` > class A; end; puts A.new.class
A
nilclass B <A; end; puts B.new.class
B
nil
class C <Geom::Transformation; end; puts C.new.class
Geom::Transformation
nil(Ignore the "nil"s -- they are unused return values.)`
How is it that C.new does not return an object with class C?
How/why does a class derived from Geom::Transform lose its identity?
How can I fix this -- I have a special coordinate system in my plugin and need to distinguish transformations using it from transformations using the standard coordinates.Note that Transformations are complicated enough that I don't want to implement them myself; I would surely get something wrong. I suppose I could make my transformation class have an instance of Geom::Transformation as a class object, but that means I need to implement a large number of functions that just pass through to that object....
-
This seems to happen for all GEOM classes (Point3d, Vector3d).
Frankly, I don't see why, and there must be an unknown or secret Ruby mechanism behind. Probably the Geom classes are proxies to C code and do not have all the bell and whitstles of normal SU object classes.
I am sure Dan will have an enlightning explanation.
Fredo
-
@fredo6 said:
I am sure Dan will have an enlightning explanation.
I will pass.
Let the "official" representatives of SketchUp explain their API's behavior.
-
I'm watching and discussing internally....
from what I can gather, the behavior is just plain ol' incorrect. We are actually looking at fixing it in a future release. But I realize that will not help with backwards compatibility. At this point, we could find no way to make it work the way you want for the classes that are broken.
Chris
-
An alternative, which I use myself, is to put all the methods etc you had intended for the sub-class into a module and perform an instance extend after you have the Geom::Point3d instance.
You can see the module I use in TT_Lib2 for instance: https://bitbucket.org/thomthom/tt-library-2/src/2bb264f27d9bc00c1b1f9a969e481c19385042ad/TT_Lib2/point3d_ex.rb?at=Version%202.9
When I receive a Point3D object I can use: point.extend(TT::Point3d_Ex)
From that point on all the content of that module is available for that instance. -
The strange thing about subclassing Geom::Transformation (or Geom::Point3d) is that it does not even execute the
initialize
method of the inherited class.For instance
class A < Geom;;Transformation ; def initialize() ; puts "Self = #{self}" ; end ; end nil a = A.new #<Geom;;Transformation;0xc808ae8>
There must be a trick since I have no clue how Ruby can do that, even if the
initialize
method of Geom::Transformation is a singleton method.Fredo
-
That's because SketchUp used an old method of allocating and initializing the data for the classes defined in C. The allocation is done explicitly in .new - which was something one had to do in Ruby 1.6. I noticed this myself when I tried to initialize an instance in Ruby C Extension using rb_class_new_instance - which failed. I had to explicitly call the .new method of the SketchUp classes.
-
Subclassing SketchUp's core classes is currently impossible (see my tries with
[extend()](https://bitbucket.org/Aerilius/color/src/e837419cfb80a5b29fb2c152a107447737f03f53/ae_Color.rb?at)
ing the returned object).@unknownuser said:
How can I fix this -- I have a special coordinate system in my plugin and need to distinguish transformations using it from transformations using the standard coordinates.
Try to create maybe a wrapper class, instead of a subclass? Create a class that stores the Geom::Transformation in a variable, and create derived methods to access/modify the original transformation.
-
.extend should work... It has worked for Geom::Point3d classes for me. Not tried Transformation, but it'd be surprised if it's different.
-
Thank you all for the discussion and suggestions.
I had not known about .extend() -- it works well, and does precisely what I wanted to do: distinguish different types of transformations (I use .respond_to? to tell if this instance is normal or special, and then use the function only for special ones). This is sort of "inverted inheritance", which is a very Ruby-ish thing to do .
-
If you extend and instance with module "FooBar" then you can use instance.is_a?(FooBar)
Advertisement