views:

286

answers:

2

Hello,

I was told more than once that Delphi handles dynamic classes better than static.Thereby using the following:

type Tsomeclass=class(TObject)
  private procedure proc1;
  public 
    someint:integer;
    procedure proc2;
end;

var someclass:TSomeclass;

implementation

...

initialization
  someclass:=TSomeclass.Create;
finalization
  someclass.Free;

rather than

type Tsomeclass=class
  private class procedure proc1;
  public 
    class var someint:integer;
    class procedure proc2;
end;

90% of the classes in the project I'm working on have and need only one instance.Do I really have to use the first way for using those classes? Is it better optimized,handled by Delphi?

Sorry,I have no arguments to backup this hypothesis,but I want an expert's opinion.

Thanks in advance!

A: 

Are you saying one instance or no instances?

With your second example, you can't instantiate that.

I've yet to see anyone use Static classes in production code. You can still declare static (class) methods in your first example.

Use a regular typed class, but declare class var, class procedure, and class function(). You can call the class methods and reference the class variables without creating an instance.

Like this:

type
  TSomeClass = class(TObject)
    class var
      somevar: String;
    class procedure Hello;
  end;

Note that class variables were added somewhere after Delphi 7, but you should definitely be able to do class methods.

Marcus Adams
Currently one instance,but if they were static then none.
John
Why first example? If I don't initiate it,I can use TsomeClass.proc1 or TSomeClass.proc2.Could you please answer the main question - what is more efficient,better optimized and better handled by Delphi?
John
@John, yes. You can use class methods and variables without instantiating an object, exactly like `TSomeClass.proc1()`.
Marcus Adams
But is it going to be better optimized or how do I say - faster, than the first way (by creating an instance of the class).
John
Instantiating the object if you don't need it will make it slower. Don't bother creating an instance if you don't need it.
Marcus Adams
+9  A: 

If you create a class that contains only class variables and class methods then you can use it without the instantiation. I.e. in your second example you could use Tsomeclass.proc2 (but not Tsomeclass.someint because this variable was not marked with the 'class' prefix as the Uwe pointed out).

For (unmesureably small) speed difference you can also mark your class methods as 'static'.

type
  TSomeclass = class
    class procedure proc2; static;
  end;

There's no "handle better" comparison in my opinion here. Delphi allows you to put 'normal' and 'class' members in the class. Former you can use only on an instantiated object and latter you can use anywhere. But that's just two parts of the OO support in Delphi.

EDIT: To answer the question about the speed ...

Let's put together a small test program:

program Project61;

{$APPTYPE CONSOLE}

type
  TTestClass = class
    procedure A(a: integer);
    class procedure B(b: integer);
    class procedure C(c: integer); static;
  end;

procedure TTestClass.A(a: integer); begin end;
class procedure TTestClass.B(b: integer); begin end;
class procedure TTestClass.C(c: integer); begin end;

var
  tc: TTestClass;

begin
  tc := TTestClass.Create;
  tc.A(42);
  tc.B(42);
  tc.C(42);
  tc.Free;
  //TTestClass.A(42); // not possible
  TTestClass.B(42);
  TTestClass.C(42);
end.

Delphi 2010 with enabled optimisation compiles .A/.B/.C calls into

Project61.dpr.30: tc := TTestClass.Create;
004060C5 B201             mov dl,$01
004060C7 A154594000       mov eax,[$00405954]
004060CC E847DAFFFF       call TObject.Create
004060D1 8BD8             mov ebx,eax
Project61.dpr.31: tc.A(42);
004060D3 BA2A000000       mov edx,$0000002a
004060D8 8BC3             mov eax,ebx
004060DA E899F9FFFF       call TTestClass.A
Project61.dpr.32: tc.B(42);
004060DF BA2A000000       mov edx,$0000002a
004060E4 8B03             mov eax,[ebx]
004060E6 E891F9FFFF       call TTestClass.B
Project61.dpr.33: tc.C(42);
004060EB B82A000000       mov eax,$0000002a
004060F0 E88BF9FFFF       call TTestClass.C
Project61.dpr.34: tc.Free;
004060F5 8BC3             mov eax,ebx
004060F7 E84CDAFFFF       call TObject.Free
Project61.dpr.36: TTestClass.B(42);
004060FC BA2A000000       mov edx,$0000002a
00406101 A154594000       mov eax,[$00405954]
00406106 E871F9FFFF       call TTestClass.B
Project61.dpr.37: TTestClass.C(42);
0040610B B82A000000       mov eax,$0000002a
00406110 E86BF9FFFF       call TTestClass.C

The object is first created and its address is stored away into the ebx register.

To call tc.A, compiler prepares parameter (42 or $2A) in edx, the address of the 'tc' instance in the eax and calls TTestClass.A.

Almost the same happens in the tc.B case except that ebx is dereferenced.

In .A and .B case, eax contains the value of the 'Self' (equivalent to C++'s 'this'). When tc.A is called, eax contains the address of the 'tc' instance. When tc.B is called, eax contains something else (I'm guessing it's pointing to the type info for the TTestClass but I'm not really sure about that).

When the code calls tc.C, only eax is prepared because 'static' methods can't reference the 'Self'.

Similar situation occurs in the TTestClass.B/.C cases except that 'Self' is loaded from some constant location when ??address of the TTestClass typeinfo?? is stored. Anyway, eax contains the same value when B is called via the instance (tc.B) or via the class (TTestClass.B).

So you can see that static calls require one 'mov' less. That was the inmesurable speedup I was refering to.

gabr
But you said speed,I don't understand.Is the first way(in my question) faster than your way(class method+static and no instance)?
John
See also second chapter of the Delphi in a Nutshell: http://oreilly.com/catalog/delphi/chapter/ch02.html
gabr