Delphi Class Helper RTTI GetMethod - delphi

Lets say I have a sample class helper
TSampleClassHelper = class helper for TSampleClass
public
procedure SomeHelper;
end;
I do the following:
var
obj :TSampleClass;
begin
obj:=TSampleClass.Create;
obj.SomeHelper;
end;
and this works as expected.
But how can I use RTTI to invoke the helper method instead? The following does not seem to work, GetMethod returns nil.
var
obj :TSampleClass;
ctx :TRTTIContext;
rtype :TRTTIType;
rmethod :TRTTIMethod;
begin
obj:=TSampleClass.Create;
rtype:=ctx.GetType(obj.ClassType);
rmethod:=rtype.GetMethod('SomeHelper'); // rmethod is nil !
end;
So does RTTI not work for methods defined in class helpers? Is there anyway around this?
Thanks.

The reason your code returns a nil method is that the object's type does not contain a method named SomeHelper. The type that contains that method is the helper type.
So, you could write this which will return a non-nil method:
obj:=TSampleClass.Create;
rtype:=ctx.GetType(TypeInfo(TSampleClassHelper));
rmethod:=rtype.GetMethod('SomeHelper');
Of course, you should immediately see the first problem, namely the use of a compile time specified type, TSampleClassHelper. Can we use RTTI to discover TSampleClassHelper at run time based on the type of the instance? No we cannot, as I will explain below.
Even if we put that to one side, as far as I can see, there's no way to invoke the method using RTTI. If you call rmethod.Invoke(obj, []) then the code in TRttiInstanceMethodEx.DispatchInvoke blocks an attempt to call the helper method. It blocks it because it decrees that the type of the instance is not compatible with the class of the method. The pertinent code is:
if (cls <> nil) and not cls.InheritsFrom(TRttiInstanceType(Parent).MetaclassType) then
raise EInvalidCast.CreateRes(#SInvalidCast);
Well, you can obtain the code address of the helper method with rmethod.CodeAddress but you'll need to find some other way to invoke that method. It's easy enough to cast it to a method with the appropriate signature and invoke it. But why bother with rmethod.CodeAddress in any case? Why not use TSomeHelperClass.SomeMethod and cut RTTI out of the loop?
Discussion
Helper resolution is performed statically based on the active helper at the point of compilation. Once you attempt to invoke a helper method using RTTI there is no active helper. You've long since finished compiling. So you have to decide which helper class to use. At which point, you don't need RTTI.
The fundamental issue here is that class helper method resolution is fundamentally a static process performed using the context of the compiler. Since there is not compiler context at run time, class helper method resolution cannot be performed using RTTI.
For more insight into this have a read of Allen Bauer's answer here: Find all Class Helpers in Delphi at runtime using RTTI?

Related

A common ancestor for of object delegates in Delphi

Is there some common ancestor for Delphi delegates which are declared with of object clause?
I need to find a common ancestor for TNotifyEvent and my custom delegate:
TMyEvent = procedure(Sender: TObject; msg: stringh); of object;
to make an universal method for firing these events.
Should I use Pointer? or TObject?
You need to get down and dirty with the implementation details for method pointers. These are stored as a so-called double pointer value. One pointer for the subject of the method call (the instance) and one pointer for the method itself (the code).
You can use the type TMethod from the System unit to represent method pointers. Its declaration looks like so (with the comparison operators removed for simplicity):
type
TMethod = record
Code, Data: Pointer;
end;
You need to use a typecast to make assignments between these types:
uses
System.Classes;
var
Event: TNotifyEvent;
Method: TMethod;
begin
Method := TMethod(Event);
TMethod(Event) := Method;
end.
Obviously none of this is type-safe so you need to ensure correctness. The compiler cannot help you. There is nothing like the checked type conversion operator, as, to work with method pointers. That is, it is up to you that when you cast from TMethod to a specific method pointer type, you have to make sure that the TMethod instance really is an instance of the method pointer type to which you cast. Think of this whole process as being analogous to casting from a typed pointer to an untyped pointer, and then back again.
Now, if you are going to store arbitrary method pointers into TMethod instances, that's fine. But what happens when you subsequently need to fire these methods. You need to know which type of method pointer is really behind each TMethod instance. So that you know how to cast it, what arguments it needs, and so how to call it. That's going to mean you have to store extra information about the true type of the method, alongside the raw method itself.
So, I think that I have perhaps answered the question that you asked, but I'm not sure it's going to be of much use to you. To understand that I think we'd really need to know more about what you are trying to achieve, and what information you have, when.
For instance, if you know the arguments that are to be passed to the method at the time you need to store it away, you could use variable capture and wrap it in an anonymous method. That would allow you to retain type-safety and avoid any of the rather dubious casts that I demonstrate above. Perhaps you need partial application, as a means of adapting your non-homogeneous method pointers to have the same interface. In which case again anonymous methods can help.

Can I make the compiler fail if Create is called explicitly?

I have many singletons where I don't want the developers to call the constructor Create. Instead they should use the function Instance
TdgpBankBranch = class(TDataGroup)
strict private
class var InstanceVar : TdgpBankBranch;
private
{ Only for internal use }
constructor Create (AOwner : TComponent); reintroduce;
protected
public
class function Instance : TdgpBankBranch;
class function Is_A_Live_Singleton: boolean;
property Rec[Bank, Branch : integer]: TBankBranch read GetRec; default;
end;
I have been shifting the constructors to private. This makes the code analysers complain "Non-public constructor".
I could shift them back to public. Is there a way to make the compiler fail if an attempt is made at using the constructor ?
Moving the constructor to private will prevent other units from being able to call Create() directly, however code inside the same unit as the class will still be able to call it unhindered, due to implicit friendship within a unit. If you don't want any code outside of the class calling Create() directly, even in the same unit, then declare it as strict private so only the class itself can call it directly.
You ask how to stop the compiler from creating an object when somebody calls .create, but what you're trying to do is create a singleton, so it helps to see how others solved this.
In Delphi, singletons are often implemented via a function that's declared in the interface section and which returns an object that's declared in the implementation section of a unit. The function creates the instance if it doesn't exist yet, to provide lazy loading. Cleanup is done via the finalization section.
In your situation, instead of having an instance() function, you just create a global function that gives you an instance.
This approach probably stems from the days before classes and private sections existed, but it's pretty straightforward, and prevents the issue that you're running in to. Look at how TClipboard is implemented. This implementation is not possible in Java or C# because they don't have global functions, or the type of scoping that makes this Delphi implementation work...
Or take a look at this answer by David Heffernan:
Delphi Singleton Pattern
It's even better than TClipboard, because it hides the entire class in the implementation section, truly preventing people to create instances themselves, but you'll have to create an interface for your class.

Fatal error: Call to protected method TCPDF::_dounderlinew() from context

I'm trying to used a method called _dounderlinew(). I'm studying the other method that was list down on the documentation of TCPDF, and it was says that this method's access is PROTECTED. This is the reason why I can't make it work just like the others. Hmm Can anyone explain me why I'm getting errors like this and how can I used this method? THANKS.
Codes I USeds
$pdf->_dounderlinew(x, y, '');
_dounderlinew() is protected because it is used in the TCPDF class to output the actual PDF code, based on your input, so it is of no use to you. As the PHP manual says:
Members declared protected can be accessed only within the class
itself and by inherited and parent classes.
By using it I assume you wish to underline text (maybe inside a cell), for that you can use the SetFont function and set the style parameter to 'U':
SetFont($family, $style='U', $size=null, $fontfile='', $subset='default', $out=true)
And the other parameters as you wish of course.

Is it required to call base method when deriving from TObject?

I have a class that descents from TObject, if I do not call the parent method, is it bad? I ask because when looking at TObject.Create/Destroy, they do nothing.
That's why we override/expose them ourselves.
There's no code example, I just want to make sure.
The most common behaviour is to call inherited. So if I explicitly do not want the inherited behaviour, I do not call inherited. Otherwise, I do. If the inherited behaviour is a no-op like TObject.Create/Destroy, I still call inherited.
Note also that the situtation for constructors and destructors is perhaps a little different than for other methods. It's exceptionally rare that you would need to skip a call to the inherited method. I cannot think of an example. Invariably constructors are creating and destroying other objects, so how could you contemplate skipping that?
I know that some authors write code that omits inherited when deriving directly from TObject, because they know that the implementation in TObject does nothing. I do not like that and to me it is a mistake to do that. The implementation details of TObject should not be leaking into derived classes.
I'm pretty sure that TObject.Create/Destroy will always be no-ops. If Embarcadero changed that then so much code would break. But what about one of your classes. Suppose you have a class derived from TObject. And then you have another class derived from that:
TMyClass1 = class
....
end;
TMyClass2 = class(TMyClass)
....
end;
You have no constructor for TMyClass1 and a constructor for TMyClass2 that looks like this:
constructor TMyClass2.Create;
begin
// no need to call inherited, it's a no-op
FMyObj := TBlahBlah.Create;
end;
Then one day you modify the TMyClass1 constructor to do something. Now TClass2 is broken. So, I would never ever omit a call to inherited because that call does nothing.
The situation for normal instance methods is a little different. It is more plausible that you want to ignore the base class implementation and provide a brand new implementation. But take the decision based on what the derived class wants to do rather than whether or not the super class has an empty implementation for the method.
You only need to call inherited if you want the code of the ancestors to execute. Sometimtes you need that code, sometimes you do not. You can also use conditionals and call inherited only if some condition is fulfilled, and you can choose when to do it (beginning of method, end of method, ...).
Hence, it all depends on the situation.
Here's an example.
Even though TObject's Create/Destroy methods don't do anything in the current version, they might in some future version (unlikely, but still might). So is it a MUST for you right now? No, because it won't accomplish anything, but only because the current parent doesn't add any functionality.
If you want your descendant objects to always add functionality to their parents, it would probably be a good idea to consistently call inherited.

InstanceClass.NewInstance vs InstanceClass.Create

what different between InstanceClass.NewInstance+Instance.Create and InstanceClass.Create;
Method1:
Instance := TComponent(InstanceClass.NewInstance);
Instance.Create(Self);
Method2:
Instance := InstanceClass.Create(Self);
Which is better?
I would always use InstanceClass.Create if it is appropriate – and invariably it is.
There are plenty of reasons. A very good one is that the single line version is more concise. Another is that the single line version is the standard, commonly used approach.
Yet another reason is the handling of exceptions in the constructor which your method 1 does not manage correctly. In case of an exception, the new instance will be destroyed, but the instance variable has still been assigned to. That's an important difference from method 2 and goes against all the lifetime management conventions of Delphi.
You mention TApplication.CreateForm. Let's take a look at it:
Instance := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := Instance;
try
Instance.Create(Self);
except
TComponent(Reference) := nil;
raise;
end;
Remember that Reference is the form variable that you pass as a var parameter. The point about this is this code assigns that form variable before calling the constructor. Normally that assignment is only made after the constructor completes.
Presumably this is so that code which references the form variable (often a global variable) can work even if it is invoked from inside that form's constructor. This is a very special case and is overwhelmingly the exception rather than the rule. Don't let this special case drive your mainstream coding style.
(I added this answer, because IMHO others where not complete)
Method 2 is the correct one.
Method 1 if never to be called, since there is an hidden parameter to the constructor call, which may fail proper iniatialize: in fact, NewInstance is a per-class pseudo virtual method!
In fact, there is an hidden boolean parameter at constructor call (register EDX, since EAX=class). As stated by official documentation:
Constructors and destructors use the same calling conventions as other
methods, except that an additional Boolean flag parameter is passed to
indicate the context of the constructor or destructor call.
A value of False in the flag parameter of a constructor call indicates that the constructor was invoked through an instance object
or using the inherited keyword. In this case, the constructor behaves
like an ordinary method. A value of True in the flag parameter of a
constructor call indicates that the constructor was invoked through a
class reference. In this case, the constructor creates an instance of
the class given by Self, and returns a reference to the newly created
object in EAX.
In particular, when called that way, the class won't call the _ClassCreate function. It may fail to initialize the class, if the class is not to be created with the default NewInstance function. In fact, this function is inserted into the class VMT: in some rare cases, it may be overloaded (e.g. to provide another memory allocation pattern - may be a garbage collector or some speed-optimized allocator). So calling directly InstanceClass.NewInstance can be buggy, in some border cases.
function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
asm
...
TEST DL,DL
JL ##noAlloc
CALL dword ptr [EAX].vmtNewInstance
##noAlloc:
...
Therefore, calling InstanceClass.NewInstance directly is only to be done on purpose, only if you want to cancel two overridden vmtNewInstance / vmtFreeInstance (and in this case, you may have to also NOT call .Free / .Destroy, but you own memory free function). So: never call NewInstance, but the constructor, as designed and documented by Embarcadero (and FreePascal team by the way), unless you need to make some internal low-level tweak.
NEVER use method 1 to create an object! It may work 99.9 % of the time, but may fail some cases, or with a compiler/RTL enhancement in the future (like a garbage collector). Even if the VCL sometimes uses NewInstance, you should not use it - I would rather prefer this method to be made protected.
Second is better because it is a standard method to create a class instance, while procedural form should be used within constructor to call inherited constructor.

Resources