• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 526
  • Last Modified:

Delphi Types Question

Hi All,

I am having a problem understanding the Type declared below and what is its benefit / usage...so can someone please help me by explaining it to me?

As far as I understand a type like ( TMyNewType = (rcKeys, rcValues, rcData); ) is a set of enumeration where I can define a new Type to be used later in the unit.  But I can't understand function/ procedure types...what they are ? what is their benefit/ usage? What are their usage conditions?

===============================================
unit RegSearch;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Forms;

type
  TRegOnProgress = procedure(const RegCurrentPath: string; const Keys,
Values, DataValues: int64) of object;

TRegSearch = class(TComponent)
.
.
.
===============================================

And in Unit1 where i use the unit RegSearch

===============================================

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Buttons, StdCtrls, Dialogs, ExtCtrls, Menus, ComCtrls, RegSearch;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    procedure RegOnProgress(const RegCurrentPath: string; const Keys,
Values, DataValues: int64);
.
.
.
procedure TForm1.RegOnProgress(const RegCurrentPath: string; const Keys,
Values, DataValues: int64);
begin

end;
//------------------------------------------------------------------------------

===============================================
Thanks in advance
0
GiantMatrix
Asked:
GiantMatrix
  • 7
  • 5
  • 4
  • +1
3 Solutions
 
JaccoCommented:
You can use them to create event properties.

For example

property OnProgress: TRegOnProgress read fOnProgress;

Now say your form has two procedures of this type:

procedure TForm1.RegProc1(const RegCurrentPath: string; const Keys, Values, DataValues: int64);
begin
  ...
end;

procedure TForm1.RegProc2(const RegCurrentPath: string; const Keys, Values, DataValues: int64);
begin
  ...
end;

Now you can set the property to one of the two:

OnProgress := RegProc1;

To execute the event just use the following code:

if Assigned(OnProgress) then
  OnProgress('RegPath', 0, 3, 5);

This is only one of there uses. I will explain another one in the next post

Regards Jacco

0
 
JaccoCommented:
You can also pass a procedure as a parameter using this technique.

Say you have the procedures in place like I mentioned above: RegProc1 and RegProc2. You can now make another method that takes a procedure as a param:

procedure TForm1.DoStuff(aProc: TRegOnProgress);
begin
  aProc('RegPath', 0, 3, 5);
end;

This calls the procedure you pass.

Have fun

Regards Jacco
0
 
GiantMatrixAuthor Commented:
Jacco,

Thanks a lot for your reply and help...please don't get upset but I am sorry to say I didn't understand your reply...so can you please elaborate more or give me another simple example?

Thanks in advance
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
JaccoCommented:
It is the same as a TNotifyEvent which is actually defined as:

type
  TNotifyEvent = procedure(Sender: TObject) of object;

If you have a form with some methods like this:

procedure TForm1.Button1Click(Sender: TObject);

and

procedure TForm1.Button2Click(Sender: TObject);

They are both compatible with the class TNotifyEvent.

A button has a OnClick event property which can be assigned any procedure that has the same signature as the procedural type definition of TNotifyEvent. So both Button1Click and Button2Click can be assigned to any TButton.OnClick event property.

Now TNotifyEvent is already predefined but Delphi lets you also define types yourself like the one you mention above TRegOnProgress where you can specify a different parameter signature.

Regards Jacco
0
 
GiantMatrixAuthor Commented:
Jacco,

But TNotifyEvent is a type that belong to a class, but the types defined in my example does not belong to any class they simply belong to the RegSearch unit.

So I can't see any relation between them

Jacco, just not to waste your time do you have to know any refrence I can read to learn more about those Types so that I can have a bit of a background?

thanks in advance
0
 
ZhaawZSoftware DeveloperCommented:
>> TMyNewType = (rcKeys, rcValues, rcData);

This allows you to specify type TMyNewType for variable and it will be allowed to use 1 of three values with it - rcKeys, rcValues or rcData. However it's possible that variable of TMyNewType type will have an "invalid" value if you do not specify any default value. Here's a small test:

[source]
type
  TTestType = (valA, valB, valC, valD, valE);
var
  TestVar : TTestType;
begin
ShowMessageFmt(
  'valA = %d'#13#10+
  'valB = %d'#13#10+
  'valC = %d'#13#10+
  'valD = %d'#13#10+
  'valE = %d'#13#10#13#10+
  'TestVar = %d', [
    integer(valA),
    integer(valB),
    integer(valC),
    integer(valD),
    integer(valE),
    integer(TestVar)
  ]
);
if TestVar in [valA, valB, valC, valD, valE] then ShowMessage('valid value') else ShowMessage('invalid value');
TestVar := valD;
if TestVar in [valA, valB, valC, valD, valE] then ShowMessage('valid value') else ShowMessage('invalid value');
inc(testVar, 2);
if TestVar in [valA, valB, valC, valD, valE] then ShowMessage('valid value') else ShowMessage('invalid value');
end;
[/source]

Here we can se that actually valA, valB, valC, valD and valE can be represented as integer values, i.e., they ARE integers that are just called differently. And by default variable of type TTestType does NOT accept any value that is not in set of [valA, valB, valC, valD, valE] (i.e., you can't do like "TestVar := 10"), however if you act with this variable as if it were integer, then you may get "invalid" values in it. Just keep this in mind if you get some errors sometimes ;)

One of most frequently usages of this kind of type are sets of values (sometimes it makes programmer's life easier):

[source]
type
  TTestType = (valA, valB, valC, valD, valE);
  TTestTypeSet = set of TTestType;
[/source]


------------------------------------------------
>> TRegOnProgress = procedure(const RegCurrentPath: string; const Keys, Values, DataValues: int64) of object;

Looks like a type of procedure for object's events. Haven't worked with these so I'll let other ppl to tell you about "procedure of object" :)

However, here's a small and simple example with plain functions/procedures:

[source]
type
  TCalculate = function (num1, num2 : integer) : integer;

function addition (num1, num2 : integer) : integer;
begin
result := num1 + num2;
end;

function deduction (num1, num2 : integer) : integer;
begin
result := num1 - num2;
end;

function multiplication (num1, num2 : integer) : integer;
begin
result := num1 * num2;
end;

function division (num1, num2 : integer) : integer;
begin
result := num1 div num2;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  calc : TCalculate;
  n1, n2 : integer;
begin
n1 := 200;
n2 := 33;
calc := addition;
ShowMessageFmt('%d', [calc(n1, n2)]);
calc := deduction;
ShowMessageFmt('%d', [calc(n1, n2)]);
calc := multiplication;
ShowMessageFmt('%d', [calc(n1, n2)]);
calc := division;
ShowMessageFmt('%d', [calc(n1, n2)]);
end;
[/source]

As you can see, this is very simple example, however there are situations when such things are used to improve performance (so you don't have to check each time which function to call; you just assign it to variable once and then use this variable as a function) or just to make it easier to read the code.

You may also use such functions between .dll and .exe files.



Hope this helps. Let me know if you need some more examples.
0
 
JaccoCommented:
When you drop TRegSearch component on the form look on the ObjectInspector and switch its tab to Events you will probably see an RegOnProgress property. When you double click it Delphi will create an empty procedure TForm1.RegOnProgress in the published section of the form for you.

The event property RegOnProgress of the TRegSearch component is now linked to this method, just like an Button1Click would be linked to the Button1.OnClick event.

See it as a callback mechanism for the TRegSearch component. The TRegSearch component is now able to call the method of your form!

Delphi uses the type information to see what published methods match the signature so that the dropdown box on the object inspector shows the correct methods when you drop it down. I.e. only method complying with the TNotifyEvent signature will show when you use the dropdown box on a Button.OnClick and only method that have the signature of TRegOnProgress will show up when you use it on the RegOnProgress property of the TRegSearch component.

A good learning source is the VCL code. It comes with Delphi professional. A way of making yourself familiar with the uses it trying to make a component yourself.

Regards Jacco
0
 
GiantMatrixAuthor Commented:
ZhaawZ,

Wow...what an explanation...thank you so much for your "detailed" reply :)

Now as of this part
>> TMyNewType = (rcKeys, rcValues, rcData);

Your example simply made it more and more clear in my mind, but just one last question...can you please explain to me what is meant by

TTestTypeSet = set of TTestType;

I mean what is its usage and how it makes programmers life easier?

Thanks in advance.
0
 
ZhaawZSoftware DeveloperCommented:
Well.. have you worked with font styles? That's the first thing that comes in my mind, hehe

Few examples:

[source]
// empty set - remove all values
Edit1.Font.Style := [];
// set only 1 value
Edit1.Font.Style := [fsBold];
// set 2 values
Edit1.Font.Style := [fsBold, fsItalic];
// remove from previous values 1 value and add 1 value
Edit1.Font.Style := Edit1.Font.Style - [fsBold] + [fsStrikeOut];
// check if value is in set
if fsItalic in Edit1.Font.Style then ShowMessage('is italic') else ShowMessage('isn`t italic');
[/source]

Edit1.Font.Style is a set of (fsBold, fsItalic, fsUnderline, fsStrikeOut)

[source]
type
  TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut);
  TFontStyles = set of TFontStyle;
[/source]

So it can contain one or more of those values. Same thing with your custom sets.
0
 
ZhaawZSoftware DeveloperCommented:
About "making programmer's life easier" - you may do all this stuff also with plain integer values and "and / or / xor". Some people think that using such "set of TType" is easier and more undestandably. I like using integers and "and / or / xor" instead ;)
0
 
GiantMatrixAuthor Commented:
Hi ZhaawZ,

No this part I do understand, so I apologize if my question wasn't clear.

My question is in the following code block

[source]
type
  TTestType = (valA, valB, valC, valD, valE);
  TTestTypeSet = set of TTestType;
[/source]

What is meant by

TTestTypeSet = set of TTestType;


Is it something like for example when you make a Vector/ Pair in C++ where each vector cell represents a structure or array?

Or in other words TTestTypeSet represent a one dimensional array where each cell in this array represent a new TTestType ?

Thanks in advance
0
 
ZhaawZSoftware DeveloperCommented:
Do not know about C++...

TTestType is not an array. It's a single value. You can't assigne multiple values to it. You can assign valA OR valB OR valC etc, but you can't assign several values.
That's why sets are - to be able to add or remove value.

TTestTypeSet is a "set of values" (or "array of bits" if handling it in low level) in which each "cell" (bit) represents presence of one of values of type TTestType.

var x : TTestTypeSet;
x := [valA, valC, valE];  <-- this set shows that it has valA, valC and valE in it, but does not have valB and valD
0
 
BlackTigerXCommented:
so, for

type
  TTestType = (valA, valB, valC, valD, valE);

you can have (only one value at a time)

var
  atestType:TTestType;
begin
  atestType:=valA;
//or
  atestType:=valB;
//or
  atestType:=valC;

and for

type
  TTestTypeSet = set of TTestType;

var
  aTestTypeSet:TTestTypeSet;
begin
  aTestTypeSet:=[valA];
//or
  aTestTypeSet:=[valA, valB];
//or
  aTestTypeSet:=[valA, valB, valC];
//etc...

that's why is a "SET"
0
 
GiantMatrixAuthor Commented:
BlackTigerX, ZhaawZ,

Thank you all for your help and support concerning Sets, now I fully understand Sets :)
0
 
GiantMatrixAuthor Commented:
Hi All,

Just to make sure I understood everything correct:

A** In any unit if I wrote under "Type" and function / procedure in either of the following formats:
type
  TEvent1 = function(const param1, param1: string): boolean;
  TEvent2 = procedure(const param1, param1: string) of object;

Then I am defining a new event for the class this block of code....correct?


B** ALL the object events must be declared just in the "Type" section and before class definition...Example:

type
  TEvent1 = function(const param1, param1: string): boolean;
  TEvent2 = procedure(const param1, param1: string) of object;

TRegSearch = class(TComponent)
  private

...correct?
Here I have another question…what is the difference between events ending up with "of Object" and events not ending with "of Objects"?


C** Event definitions can either end by "of object" or not...correct?


D** Events can only be declared in any component / class, but we can not write code in the function/ procedure representing the event…correct?

Thanks in advance
0
 
JaccoCommented:
A and B are correct. You can also have funtion of object types:

TEvent1 = function(const param1, param1: string): boolean of object;

These are not used very often but occasionally I have found a use for it. You have to take special care that the implementor initialised the result he wants to pass back since you can't do that for him. That is why it is more common to use a var parameter in stead.

TEvent1 = procedure(const param1, param1: string; var Result: Boolean) of object;

"of objects" is not used. Where have you seen this?

C If "of object" is added the event must be implemented with a method of a class instance. If you define a procedural type without "of object". The Implementation is then just plain procedures or functions. This is mostly used to pass procedures (not method) as parameters or store references to procedures (not methods).

D When I understand you correctly you are correct. The implementation of the event is omitted to make the component more flexible and generic. For example a button that can do only one thing (pop up a specific screen) is not very usefull since you would need another button class for anything youwould want to do when the user clicks a button.

Regards Jacco

0
 
GiantMatrixAuthor Commented:
Jacco,

>>These are not used very often but occasionally I have found a use for it. You have to take special care that the >>implementer initialized the result he wants to pass back since you can't do that for him. That is why it is more >>common to use a var parameter in stead.
>>TEvent1 = procedure(const param1, param1: string; var Result: Boolean) of object;

I am sorry I couldn't understand this part 100% so can you please elaborate.

>>"of objects" is not used. Where have you seen this?
Here is a simple example without "of object":
type
  TEvent1 = function(const param1, param1: string): boolean;

>>If you define a procedural type without "of object". The Implementation is then just plain procedures or functions. >>This is mostly used to pass procedures (not method) as parameters or store references to procedures (not >>methods).

Can you please elaborate this part by any example?

D. Yes you understood me correctly, what I meant was that the events defined for any component/ class won't have a corresponding in the implementation.

Thanks in advance
0
 
BlackTigerXCommented:
when you include "of object", then that's a METHOD signature

a method, is a function or procedure that is INSIDE a class

//these are methods
TMyClass = class
  procedure Method1();
  funcion Method2():Boolean;
end;

TMyClass.Method1();
begin
end;

TMyClass.Method2():Boolean;
begin
end;

when you DO NOT include "of object", then is just a regular procedure, OUTSIDE of a class

procedure Method3();
begin
end;

function Method4():Boolean;
begin
end;

you use one or another depending on the situation, for example when hooking to functions on the  Windows API, you normally do not use "of object" because they are just plain procedures or functions
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 7
  • 5
  • 4
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now