Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
Hi BrowserUK,

Glad to be able to make you think a bit! Let me try to respond to a few of your comments. But first, we should be clearer about our definitions of reflection. I'm including in my definition finding the type of an object (using Java.Lang.Class in Java or typeof in C++ or ref in Perl), and testing whether an object inherits from another object (using instanceof in Java or dynamic_cast in C++ or isa in Perl. If you don't consider these reflection, and are only thinking of getting the methods and member variables of a class, some of my examples don't really use reflection.

You will have to know what type of shape is is, in order to instantiate the object
Right, this part doesn't use reflection.
For your intersection problem, any language that supports method overloading, C++, Java etc., will allow you to code methods within your Rect subclass with signatures of:
class Rect; bool intersect( Rect* ); bool intersect( Ellipse* ); bool +intersect( Polygon* ); ...
So that invoking someRect->intersect( someShape ); will get to the right code without introspection.
This is called "dynamic dispatch" IIRC and the behavior I would like and expect, but unfortunately not the behavior exhibited by either Java or C++. Both determine which overload of a function/method to call at compile-time, and if all you know about the object is that it's a Shape* it will always call the overload for that type. For example, in C++:
#include <iostream> using namespace std; class Shape { public: virtual ~Shape(){}; }; class Polygon : public Shape { }; class Circle : public Shape { }; void ShowType(Shape *obj) { cout << "Shape" << endl; } void ShowType(Polygon *obj) { cout << "Polygon" << endl; } void ShowType(Circle *obj) { cout << "Circle" << endl; } int main() { Shape *shape; shape = new Polygon(); ShowType(shape); shape = new Circle(); ShowType(shape); }
Shape Shape

To make it work, we have to use runtime reflection:

void ShowType(Shape *obj) { if (dynamic_cast<Polygon*>(obj)) ShowType(dynamic_cast<Polygon*>(obj)); else if (dynamic_cast<Circle*>(obj)) ShowType(dynamic_cast<Circle*>(obj)); else cout << "Shape" << endl; }
Polygon Circle

This is why the distinction between knowing the type at compile-time versus runtime is important; if the compiler knows the type it can call the correct overload, otherwise it will not.

For the "make sure it was a type I could deal with" part of the equation, if all plug-ins are derived from a base class, then the only check required is to verify that the class loaded is derived from that base class.
Right, but IIRC the class loading code returns a Class and you have to use runtime type checking to determine if it is the right sort of class.
Once the class is loaded, try instantiating a (minimal) instance, and exercising the required methods. Catch and report any errors. You can even check that the loaded class methods return sensible values--And that's something that no amount of reflection can do. All your validation is performed immediately after loading.
While this is possible, it is error-prone, and violates the concept of putting things in exactly one place. If I add a new method to my class, I have to remember to go add a check for that method to all places where it is loaded dynamically. If it is loaded dynamically from 3rd party code, I have to notify those parties to check for this new method. The maintenance cost is much higher than the runtime cost of doing this check, IMHO.

I think what you are saying here is that you can use reflection to construct a workaround to the quirk, not detect the need for it
I'm actually simply saying to detect a need for it, by looking at the type of the object.
the classic solution to this is to construct a subclass that inherits from the quirky class and override the troublesome methods
Easier said than done if your code is a library being used by other programs who are creating the object in question and passing it in. All users of your code would have to switch to your subclass, then switch back when the bug in the original code is fixed, which is a maintenance nightmare.

As far as the cost of keeping type information and reflection information around, I'm not quite sure what the cost is in different languages. I think it's quite low for C++ RTTI, and I think Perl has to keep that information around anyways, so it's also quite low. But I haven't really seen reflection overused; it seems to be just inconvenient enough that it doesn't get used unless there is a genuine need.

In reply to Re^3: Runtime introspection: What good is it? by sgifford
in thread Runtime introspection: What good is it? by BrowserUk

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (2)
As of 2023-09-22 18:56 GMT
Find Nodes?
    Voting Booth?

    No recent polls found