Why doesn't the Delphi compiler throw a warning when a class method uses self? - delphi

At my workplace, we have some code where class functions refer to Self, effectively creating a potential access violation, should the object not be initialised. Does the meaning of Self change in a class method as to refer the class rather than the object?
I assume the only reason this is working is because the Self refers to another class function and not a regular method.
I created the following test class:
constructor TTest.Create;
begin
FTest := 'Hej';
end;
procedure TTest.GoTest;
begin
ShowMessage(FTest);
end;
class procedure TTest.Test;
begin
Self.GoTest;
end;
However, compiling this throws an error:
[dcc32 Error] Unit1.pas(51): E2076 This form of method call only allowed for class methods or constructor
I also testing referring to FTest directly, which gave another error:
[dcc32 Error] Unit1.pas(51): E2124 Instance member 'FTest' inaccessible here
But I wonder, however, whether it is possible to have a case where Self is potentially dangerous in class methods.
I know, that referring to global objects and assume they are there is always bad.

Does the meaning of Self change in a class method as to refer the class rather than the object?
In a class method Self refers to the class. The documentation says:
In the defining declaration of a class method, the identifier Self represents the class where the method is called (which can be a descendant of the class in which it is defined.) If the method is called in the class C, then Self is of the type class of C. Thus you cannot use Self to access instance fields, instance properties, and normal (object) methods. You can use Self to call constructors and other class methods, or to access class properties and class fields.
A class method can be called through a class reference or an object reference. When it is called through an object reference, the class of the object becomes the value of Self.
The compiler won't object to you using Self since it is a legal and supported thing to do. It just complains when you try to use instance members, instance methods etc.
Self has this meaning in class methods for exactly the same reason it exists in instance methods. It allows you to fully specify a symbol and thus avoid scoping ambiguity. What's more it allows you to access the actual class on which the method is called. This may be a descendant of the class in which the method is defined.
I wonder, however, whether it is possible to have a case where Self is potentially dangerous in class methods.
I don't see any particular danger inherent in this part of the language. In fact the use of Self reduces scope and so reduces the danger of inadvertently referring to a local variable rather than a class member.

Related

Why factory constructor can't be used in invoking superclass?

Minimal reproducible code:
class Foo {
Foo();
factory Foo.named() => Foo();
}
class Bar extends Foo {
Bar() : super.named(); // Error
}
As there's no async-await thing in the factory constructor, and it instantly invokes the concrete constructor, so why isn't it allowed to use factory constructor like that?
Before null safety, null could be returned from a factory constructor but it is no longer a case. So, I think a factory constructor should now be allowed.
factory function can return subclass, which means can call subclass's init function.
if subclass self can call super.factory function, then it become cycling.
Calling a generative constructor creates a new object, then runs the constructor and super-class constructors to initialize that new object.
They are initializers which initialize the object created by the (now often implicit) new operator.
The super-constructor chained by the (non-redirecting) generative constructor is called to initialize the same object, and ensure that its fields are fully initialized, before ever giving anyone access to that object.
Calling a factory constructor does not create any new object, it just executed the body of that constructor which can do anything that normal code can. (That may or may not include calling a generative constructor to create an object. It can also just throw and never create any object.) A factory constructor cannot access this, because there is no "current object" before it returns one.
Let's assume that Foo has an int foo = 42; field. A factory constructor like the Foo.named here creates a new object by calling Foo() - the generative constructor.
When you do new Bar(), you create a new Bar object and ask the super-constructors to initialize that object. The named factory constructor has no access to that new object that would be created by calling new Bar(), it cannot access this and it cannot help initialize the foo field of that object. It creates a new, unrelated, Foo object and now you have 1) a partially initialized Bar object and 2) a Foo object, neither of which can be the result of calling a Bar constructor.
Your generative constructors must call a super-class generative constructor, which does the same until reaching the Object constructor. That's the only way to ensure that the newly generated object is fully initialized.
One of the main purposes of a factory constructor is to allow returning an existing instance. That's basically incompatible with a derived class constructor that must create a new object. (I suppose it doesn't necessarily have to be; you could imagine a design where two derived instances virtually inherit from a shared instance of a base class. However, that would be a lot of extra work for something of little benefit and that could be very confusing.)
Additionally, one of the other main purposes of a factory constructor is precisely to prevent a class from being subclassed by making all non-factory constructors private.

What does the keyword "dynamic" do to a procedure?

What happens to a procedure when it is declared with the keyword dynamic?
And what is the effect of declaring it with the keyword static?
This question can be answered by reading the documentation.
The dynamic keyword introduces a method that can be overridden polymorphically. Semantically it is interchangeable with virtual, but the is implemented in a different manner. Read about it here: http://docwiki.embarcadero.com/RADStudio/en/Methods#Virtual_and_Dynamic_Methods
To make a method virtual or dynamic, include the virtual or dynamic
directive in its declaration. Virtual and dynamic methods, unlike
static methods, can be overridden in descendent classes. When an
overridden method is called, the actual (run-time) type of the class
or object used in the method call--not the declared type of the
variable--determines which implementation to activate.
To override a method, redeclare it with the override directive. An
override declaration must match the ancestor declaration in the order
and type of its parameters and in its result type (if any).
...
In Delphi for Win32, virtual and dynamic methods are semantically
equivalent. However, they differ in the implementation of method-call
dispatching at run time: virtual methods optimize for speed, while
dynamic methods optimize for code size.
In general, virtual methods are the most efficient way to implement
polymorphic behavior. Dynamic methods are useful when a base class
declares many overridable methods that are inherited by many
descendent classes in an application, but only occasionally
overridden.
Class static methods are like class methods in that they are invoked on the class rather than an instance. The difference between class static and class methods is that class methods are passed a Self pointer that contains the class, and class static methods are not. This means that class methods can be polymorphic and class static methods cannot. Read about it here: http://docwiki.embarcadero.com/RADStudio/en/Methods#Class_Static_Methods
Like class methods, class static methods can be accessed without an object reference. Unlike ordinary class methods, class static methods have no Self parameter at all. They also cannot access any instance members. (They still have access to class fields, class properties, and class methods.) Also unlike class methods, class static methods cannot be declared virtual.
With all due respect, I refer you to this question: How can I search for Delphi documentation?

Delphi - can a property read from a property?

So I just joined this forum because I could not find an answer to my simple question.
I want to declare a read-only property, and it should read from a private members read-only property. It seems like that won't work. Can I work myself around that blockade?
Here is the code snippet:
property Mine: TMineType read mMine.MineType;
Edit: Maybe I should clarify. mMine is of class TMine, which has a property MineType. MineType is of type TMineType and is read-only.
A property getter can be one of two things:
A field, or
A function.
Your code attempts to implement the getter with a property, and that does not meet the requirement stated above.
The documentation contains all the details: http://docwiki.embarcadero.com/RADStudio/en/Properties
On a practical level, you could do something like this:
function GetMineType : TMineType;
begin
result := mMine.MineType;
end;
property Mine: TMineType read GetMineType;
If you declare the GetMineType function as inline it will not generate any code.
Based on your additional information that you provided in your comments (such information should be put into the original question itself right from the start) I believe I can provide an answer which would hopefully provide solution to the problem you are facing.
In the code bellow I'm showing of how you can make parent class property accessible through descendant class by using property forwarding or property publishing.
//Base class we use
TBaseClass = class(TObject)
//Private section. Methods, fields and properties declared here are only visible from within classes declared in same unit
//but not from classes or method declared in other units.
private
FPrivateField: Integer;
function GetPrivateField: Integer;
procedure SetPrivateField(AValue: Integer);
//This property is making use of getter and setter methods in order to access FPrivateField
property PrivateFieldProperty: Integer read GetPrivateField write SetPrivateField;
//Strict private section. Methods, fields and properties declared here are only visible from descendant classes and their
//methods but not from other classes and their methods even if they are declared in the same unit.
strict private
FStrictPrivateField: Integer;
function GetStrictPrivateField: Integer;
procedure SetStrictPrivateField(AValue: Integer);
//Public section. Methods, Field and properties declared here are visible from any other class or methods regardless of
//where they are declared
public
//This property is accessing its field directly
property DirectPrivateFieldProperty: Integer read FPrivateField write FPrivateField;
//This property is making use of getter and setter methods in order to access FStrictPrivateField
property StrictPrivateFieldProperty: Integer read GetStrictPrivateField write SetStrictPrivateField;
end;
//Sub class is actually a descendant class from our base class
TSubClass = class(TBaseClass)
public
//If your parent class already has declared certain property and you want to use that property in your descendant
//class you can use so called "property forwarding" approach where you only specify the parents property name that
//you want to make available to your descendant class. This approach only allows accessing fields that are declared
//in parents class.
//If you need to access field declared in descendant class then its property must directly access that field or use
//getter and/or setter methods declared in descendant class. Such approach is called property overloading.
property DirectPrivateFieldProperty;
property PrivateFieldProperty;
//If you want to limit the access level of a descendants class property (making it read only) you need to follow standard
//property declaration guideline where you declare property type and the field to which it is accessing either directly or
//by using getter or setter methods
property ReadOnlyPrivateFieldProperty1: Integer read FPrivateField;
property ReadOnlyPrivatefieldProperty2: Integer read GetPrivateField;
//You can also declare forwarded descendant class property with different visibility of the one declared in parent class.
//Such approach is usually referred as property publishing.
property StrictPrivateFieldProperty;
end;
Note the above approaches only work when accessing properties or fields of a parent class from a descendant class but not for accessing fields or properties of other classes.
The reason for this is that property may only directly access fields of its own class or any parent classes.
Also property can only use getter and setter methods that are declared either in its own class or in any of the parent classes.
I hope this answer of mine might give you better idea about working with properties.
Now at the moment I guess properties might look a bit confusing to you but believe me when you will learn to work with them you will realize of how powerful they can actually be. I must admit that I'm still finding out new ways to use them in my projects every now and then.

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.

Delphi Use calling objects properties in added class method

I want to add a method to an existing Delphi class. I think basic class framework OK but need to access some properties of the object that called my method in my method. I can't seem to get anything to work.
old class TStringGrid
new class OptStringGrid where myNewMethod is referenced
//example of new class method
procedure myNewMethod (const Name: string);
begin
//Here is my question location.
// I would like to access properties of the calling object in this case
// testgrid. Like... i:= testgrid.rowcount;
end
// Unit Calling statements
var
testGrid : OptStringGrid;
i: integer;
begin
i := testgrid.myNewMethod(strName);
end;
New to Delphi, forgive my terminology if wrong please. I know example code not compilable. I'm looking for techniques to access the properties as described.
To access members of the object whose method is executing, you can use the Self variable. It's automatically declared and assigned inside any method body. In fact, its use is usually implicit — any members of the object are automatically in scope inside the method body. You generally only need to qualify member access with Self when there is already some other variable in the method that has the same name as the member you wish to use.
The key thing about implementing methods is that you need to make sure they're actually methods. The code shown in the question does not define myNewMethod as a method. Rather, it's a standalone subroutine. Only methods can be called on objects, and therefore only methods can have access to the objects they're called on.
A method declaration appears inside a class declaration. Yours might look something like this:
type
TOptStringGrid = class(TStringGrid)
public
function myNewMethod(const Name: string): Integer;
end;
A method definition appears in the implementation section of your unit, along with all your other subroutine bodies, just like all the event-handler implementations the IDE creates for you when you double-click events in the Object Inspector. Those are just ordinary methods.
What distinguishes a method implementation from an implementation of some other kind of subroutine is that the method name includes the name of the class it belongs to:
function TOptStringGrid.myNewMethod(const Name: string): Integer;
begin
// ...
end;
Observe the TOptStringGrid. portion in the code above. That's how the compiler knows that the method body belongs to that class and not anything else named myNewMethod.
Within that method body, you can access all the published, public, and protected members of the ancestor class, TStringGrid, including the RowCount property.

Resources