Title: Language and Compiler Features Since Delphi 7
Question: Language and Compiler Features Since Delphi 7
Answer:
Language and Compiler Features Since Delphi 7
Inline
The Delphi compiler allows functions and procedures to be tagged with the inline directive to improve performance. If the function or procedure meets certain criteria, the compiler will insert code directly, rather than generating a call. Inlining is a performance optimization that can result in faster code, but at the expense of space. Inlining always causes the compiler to produce a larger binary file. The inline directive is used in function and procedure declarations and definitions, like other directives.
Note : The inline directive is a suggestion to the compiler. There is no guarantee the compiler will inline a particular routine, as there are a number of circumstances where inlining cannot be done
Syntax example:
function AnsiCompareStr(const S1, S2: string): Integer; inline;
Operator Overloading
Delphi allows certain functions, or operators, to be overloaded within record declarations
TMyClass = class
class operator Add(a, b: TMyClass): TMyClass;
// Addition of two operands of type TMyClass
class operator Subtract(a, b: TMyClass): TMyclass;
// Subtraction of type TMyClass
class operator Implicit(a: Integer): TMyClass;
// Implicit conversion of an Integer to type TMyClass
class operator Implicit(a: TMyClass): Integer;
// Implicit conversion of TMyClass to Integer
class operator Explicit(a: Double): TMyClass;
// Explicit conversion of a Double to TMyClass
end;
// Example implementation of Add class operator
TMyClass.Add(a, b: TMyClass): TMyClass;
begin
...
end;
// Example using Add class operator
Procedure DooStuff;
var
x, y: TMyClass
begin
x := 12; // Implicit conversion from an Integer
y := x + x; // Calls TMyClass.Add(a, b: TMyClass): TMyClass
b := b + 100; // Calls TMyClass.Add(b, TMyClass.Implicit(100))
end;
Class Helpers
A class helper is a type that - when associated with another class - introduces additional method names and properties which may be used in the context of the associated class (or its descendants).
Class helpers are a way to extend a class without using inheritance. A class helper simply introduces a wider scope for the compiler to use when resolving identifiers. When you declare a class helper, you state the helper name, and the name of the class you are going to extend with the helper. You can use the class helper any place where you can legally use the extended class. The compiler's resolution scope then becomes the original class, plus the class helper. Class helpers provide a way to extend a class, but they should not be viewed as a design tool to be used when developing new code. They should be used solely for their intended purpose, which is language and platform RTL binding.
type
TMyClass = class
procedure MyProc;
function MyFunc: Integer;
end;
procedure TMyClass.MyProc;
var
X: Integer;
begin
X := MyFunc;
end;
function TMyClass.MyFunc: Integer;
begin
end;
type
TMyClassHelper = class helper for TMyClass
procedure HelloWorld;
function MyFunc: Integer;
end;
...
procedure TMyClassHelper.HelloWorld;
begin
WriteLn(Self.ClassName);
// Self refers to TMyClass type, not TMyClassHelper
end;
function TMyClassHelper.MyFunc: Integer;
begin
...
end;
var
X: TMyClass;
begin
X := TMyClass.Create;
X.MyProc; // Calls TMyClass.MyProc
X.HelloWorld; // Calls TMyClassHelper.HelloWorld
X.MyFunc; // Calls TMyClassHelper.MyFunc
end;
Strict private/protected
A member of a class declared with the strict private visibility is accessible only within the class in which it is declared - not visible to procedures or functions declared within the same unit.
A member of a class declared with the strict protected visibility is accessible within the class in which it is declared, and within any descendant class.
Here's an example:
type
TMyClass = Class
strict private
procedure StrictPrivateProcedure;
strict protected
procedure StrictProtectedProcedure;
public
procedure PublicProceudre;
End;
TMyOtherClassClass = class(TMyClass)
public
procedure OtherPublicProceudre;
end;
{ TMyClass }
procedure TMyClass.StrictPrivateProcedure;
begin
end;
procedure TMyClass.StrictProtectedProcedure;
begin
end;
procedure TMyClass.PublicProceudre;
begin
end;
{ TMyOtherClassClass }
procedure TMyOtherClassClass.OtherPublicProceudre;
begin
StrictProtectedProcedure;
StrictPrivateProcedure;
end;
This example will actually not compile because TMyOtherClassClass.OtherPublicProceudre are tyring to access TMyClass.StrictPrivateProcedure;
[Pascal Error] Unit1.pas(352): E2003 Undeclared identifier: 'StrictPrivateProcedure'
Records with Methods
In addition to fields, records now may have properties and methods (including constructors), class properties, class methods, class fields, and nested types.
The rule is that you can add only non-virtual methods, as records inheritance is not supported in Win32. You can also define a pseudo-constructor to initialize the data, but you cannot have a destructor.
The key difference between records and classes is the way they are allocated in memory. Variables having a class as type are allocated dynamically: in this case a variable is a reference to the actual memory location of the object. Variables with a record as type are allocated locally, either on the stack (for local method variables), within the containing object (for class fields), or in the global memory (for global variables).
The differences in memory allocation can cause some significant differences in the processing time (generally favoring records) and in the amount of memory used (often favoring classes).
Class
Declaring Nested Types
The nestedTypeDeclaration follows the type declaration syntax defined in Declaring Types .
type
className = class [abstract | sealed] (ancestorType)
memberList
type
nestedTypeDeclaration
memberList
end;
Nested type declarations are terminated by the first occurance of a non-identifier token, for example, procedure, class, type, and all visibility scope specifiers. The normal accessibility rules apply to nested types and their containing types. A nested type can access an instance variable (field, property, or method) of its container class, but it must have an object reference to do so. A nested type can access class fields, class properties, and class static methods without an object reference, but the normal Delphi visibility rules apply. Nested types do not increase the size of the containing class. Creating an instance of the containing class does not also create an instance of a nested type. Nested types are associated with their containing classes only by the context of their declaration.
An syntax example :
type
TClassName = class
public
Procedure P1;
Procedure P2;
type
MyNestedTypeDeclaration = Integer;
private
procedure p3(a : MyNestedTypeDeclaration);
procedure P4;
end;
Nested Classes
The following example demonstrates how to declare and access fields and methods of a nested class.
type
TOuterClass = class
strict private
myField: Integer;
public
type
TInnerClass = class
public
myInnerField: Integer;
procedure innerProc;
end;
procedure outerProc;
end;
To implement the innerProc method of the inner class, you must qualify its name with the name of the outer class. For example
procedure TOuterClass.TInnerClass.innerProc;
begin
...
end;
To access the members of the nested type, use dotted notation as with regular class member access.
For example
var
x: TOuterClass; y: TOuterClass.TInnerClass;
begin
x := TOuterClass.Create;
x.outerProc;
...
y := TOuterClass.TInnerClass.Create;
y.innerProc;
end;
Nested Constants Constants can be declared in class types in the same manner as nested type sections. Constant sections are terminated by the same tokens as nested type sections, specifically, reserved words or visibility specifiers. Typed constants are not supported, so you cannot declare nested constants of value types, such as Borland.Delphi.System.Currency , or Borland.Delphi.System.TDateTime . Nested constants can be of any simple type: ordinal, ordinal subranges, enums, strings, and real types.
The following code demonstrates the declaration of nested constants:
type
TMyClass = class
const
x = 12;
y = TMyClass.x + 23;
procedure Hello;
private
const
s = 'A string constant';
end;
begin
writeln(TMyClass.y); // Writes the value of y, 35.
end.
Class var
A class can also have a class variable, applicable only to the class and not an instance of the class.
type
TClassWithClassType = class
private
type
TRecordWithinAClass = record
SomeField: string;
end;
public
class var
RecordWithinAClass: TRecordWithinAClass;
end;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
TClassWithClassType.RecordWithinAClass.SomeField := 'This is a field of a class type declaration';
ShowMessage(TClassWithClassType.RecordWithinAClass.SomeField);
end;
Final methods
A virtual method that you override can now be marked final, preventing derived classes from overriding that method
TAbstractClass = classabstract
public
procedure Bar; virtual;
end;
TSealedClass = classsealed(TAbstractClass)
public
procedure Bar; override;
end;
TFinalMethodClass = class(TAbstractClass)
public
procedure Bar; override; final;
end;
Sealed methods
Classes marked as sealed cannot be descended from. See the example in 'final methods'
Static class methods
Classes can have static class methods -- i.e. methods that can be called from a class type. 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.
type
TMyClass = class
strict private
class var
FX: Integer;
strict protected
// Note: accessors for class properties must be declared class static.
class function GetX: Integer; static;
class procedure SetX(val: Integer); static;
public
class property X: Integer read GetX write SetX;
class procedure StatProc(s: String); static;
end;
TMyClass.X := 17;
TMyClass.StatProc('Hello');
for-in loop
Delphi 2007 for Win32 supports for-element-in-collection style iteration over containers. The following container iteration patterns are recognized by the compiler:
for Element in ArrayExpr do Stmt;
for Element in StringExpr do Stmt;
for Element in SetExpr do Stmt;
for Element in CollectionExpr do Stmt;
Localized char-set
You can now use the special characters of you own language for class names methods etc, even tough the code completion have some problems with it.
For example Im Danish. The Danish word for donkey are sel so instead of TDonkey I can write :
Type
Tsel = class
public
Procedure p1;
end;
But code completion is not prepared for it so you would have to correct it by hand.
Credits: Parts of this article was wrote by Nick Hodges in the site codegear.com
If you like this article. please rate it.