It is by design.
Replacing the native prototypes is not supported because:
- Supporting it (especially for all types) would add overhead, increase complexity and have a non-trivial cost in terms of my time.
- The native prototypes are used to identify which native methods or properties can be safely applied to the object. For instance, (Gui.Control.Prototype.Opt)(textCtrl, options) would fail because textCtrl is not derived from the prototype object originally associated with Opt. Adding Opt: Gui.Control.Prototype.Opt to your new prototype and calling textCtrl.Opt(options) would have the same result.
- The restrictions for setting Base (which are in place because of the point above) would in most cases prevent you from assigning a native prototype as the base of your new prototype. Instead, you would have to construct an instance of the original native type, and then use that as a prototype. In this case, you would have to create a Gui with a Text control, and use the Text control's object as your prototype.
- I see little reason to replace a built-in prototype. Other means of extending the built-in classes are available, and are less error-prone. For instance, if you just define each property you want, you are unlikely to end up with a control which has none of the original methods (as in your example) or that doesn't identify as a Gui.Control; and it is more likely that your script will work with other scripts that define their own properties.
Built-in types which are not intended to be instantiated directly (by calling the class) do not necessarily have __New or __Init called when they are "constructed" (even if you define them). The classes are defined only to support type checking and extension by altering the prototype's properties.
I considered making Prototype like Base, a built-in property of the Class, and might yet. I haven't because it's more work and more code (requiring not just the implementation of the property but also implementation of Class as a distinct C++ type, which is trivial to do but will increase binary size), with relatively trivial impact on scripts.
- Some operations should be faster, like instantiating classes.
- Some additional restrictions might be enforced: no setting Prototype, x is y requiring a true Class and not just any object with a Prototype, maybe others.
- Class() would create a Prototype for itself, instead of requiring the script to set one; Class(BaseClass) would probably be added to allow the construction of a Class and Prototype based on a native class other than Object.
For custom GUI controls, one idea was for
G.Add(Ctrl) to do the equivalent of
(Gui.%Ctrl%)() (which would require changing construction of controls to work more like you expect). In that case, what you should do (just hypothetically, since you probably shouldn't do it) is replace
Gui.Text itself, not its Prototype, if you want
G.Add('Text') to return a new type of control. (The proper equivalent would hypothetically be to subclass Gui and define Text in your subclass, perhaps as a nested class.)
As for classifying this as a bug or not, setting an object as Prototype does in fact cause that object to be used as the base of all future instances of the class:
Code: Select all
Gui.Text.Prototype := {__Class: 'Fubar'}
MsgBox type((Gui.Text)()) ; Fubar
If an object is not derived from Gui.Text.Prototype, it is not an instance of the Gui.Text class. Therefore,
G.Add('Text') does not create an instance of
this Gui.Text class in your case.
The documentation says the Call method (
ClassObj()) sets the base of the new object to
ClassObj.Prototype. However, who says the class is being
called?
The documentation also says Prototype retrieves or sets the object on which all instances of the class are based. However, I think it should be obvious that any new value you set isn't automatically used by all existing instances, so which instances? And what's an instance of the class anyway? GUI controls are not
constructed from the
Gui.Text class. If an instance is defined as any object derived from
Gui.Text.Prototype, they are instances of that class by default, but not after you reassign Prototype. Certainly,
textCtrl is Gui.Text is false in your case.