Recent

Author Topic: Reference counting plz?  (Read 62782 times)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12857
  • FPC developer.
Re: Reference counting plz?
« Reply #15 on: March 23, 2014, 08:53:01 pm »
Then may I ask you the following: how you deal with thread-safety? In case object is used in many threads, then one thread might set conut = 0, but then two threads at once read count = 0, then two threads will try to release the object

By using interlockedincrement/decrement.  Just like e.g. ansistrings work internally.

karaba

  • New Member
  • *
  • Posts: 49
Re: Reference counting plz?
« Reply #16 on: March 24, 2014, 05:39:35 am »
I have started to use interfaces for almost every data object

But they suck extremely, because
  • you have to declare every method twice (in the interface and the class)
Yeah try pressing ctrl+space on the class interface you should see a list of method you can override and if I'm not mistaken the interface methods are there too.
  • cannot access fields anymore
erm doesn't compute really you couldn't access them outside the class anyway.
  • are much slower than classes, because every method behaves like a virtual method.  Currently you cannot have ref-counted objects with normal methods!!
much? how much slower? slower they are.
  • cannot use TAncestor(var) casts anymore  (and it is not even a compile error, just crashes at run time)
erm as long as the var is a  class yes you can if it is an interface yeah that doesn't work.
  • you either need to implement the ref counting yourself, or cannot use inheritance at all anymore (because you need inherit TinterfacedObject and there is no multiple inheritance. Latter should be added one day, too).
true inheritance is a problem of course you can have a class that implements the basics and use the implements keyword, in which case it is easy.


It would be great, if there were a "refcounted" keyword, that just makes a class ref-counted (like an interface, but changing nothing else):

Code: [Select]
type T... = refcounted class ...

But actually, in most cases you do not need ref counting or garbage collection.

What you need are scoped objects.

Automatically created when you enter the scope, and automatically destroyed, when you leave the scope.

E.g. something like

Code: [Select]
var foobar: scoped TStringList;
would automatically call TStringList.create, assigning it to foobar, and calling foobar.free after the end;

well that is a garbage collection in my eyes though.

if the only thing you want is to avoid writing the free code then there is a class like that in jedi (JCL I think, not sure) that you can use an interface based protector that when it goes out of scope it auto destroyes the objects it protects.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12857
  • FPC developer.
Re: Reference counting plz?
« Reply #17 on: March 24, 2014, 09:37:12 am »
Scoped RAII like instantiation has been discussed before, but it also has its disadvantages:

1. There is no guard against adding it to something outside the function scope (like a tlist field in the class)
2. The allocation will be active for the whole scope
3. Like ansistring it needs an implicit try finally

And IMHO the construct (purely using an object locally in one method) is not that common enough to warrant special syntax.

BeniBela

  • Hero Member
  • *****
  • Posts: 959
    • homepage
Re: Reference counting plz?
« Reply #18 on: March 24, 2014, 11:26:59 am »
space on the class interface you should see a list of method you can override and if I'm not mistaken the interface methods are there too.

If you need an IDE to use a language efficiently it is a bad language

erm doesn't compute really you couldn't access them outside the class anyway.

You can, if they are public

much? how much slower? slower they are.

On my computer:

Class method inlined: 225 ms
Fields access: 255 ms
Class method: 366 ms
Interface method: 451 ms


That means that with a refcounted non interface, the program  would run twice as fast!

(and I am using it in an interpreter for my programming language. So I have a lot of methods doing nothing except basic arithmetic)

Code: [Select]
program Project1;

{$mode objfpc}{$H+}

uses bbdebugtools;
type
 iinc = interface
   procedure inc;
 end;

 { tc }

 tc = class(TInterfacedObject, iinc)
   x: integer;
   procedure inc;
   procedure incin;  inline;
 end;
procedure tc.inc;
begin
  x := x + 1;
end;

procedure tc.incin;
begin
  x := x + 1;
end;

var c : tc;
    i: iinc;
    j: Integer;
    k: Integer;
    r: Integer;
begin
  logging:=true;
  for r := 1 to 10 do begin
    c := tc.Create;
    i := c;
    c.x := 0;
    startTiming('field');
    for j := 1 to 100000000 do c.x:=c.x+1;
    stopTiming('field');
    c.x := 0;
    startTiming('class');
    for j := 1 to 100000000 do c.inc;
    stopTiming('class');
    c.x := 0;
    startTiming('class inline' );
    for j := 1 to 100000000 do c.incin;
    stopTiming('class inline');
    c.x := 0;
    startTiming('interface');
    for j := 1 to 100000000 do i.inc;
    stopTiming('interface');
  end;
end.


erm as long as the var is a  class

Yes, that's why I want it to be a class

yes you can if it is an interface yeah that doesn't work.

Exactly

true inheritance is a problem of course you can have a class that implements the basics and use the implements keyword, in which case it is easy.

Not if you need to inherit from a non-interface

well that is a garbage collection in my eyes though.


More like pretty syntax

Usually garbage collection means neither scopes nor ref-counting, but something like mark-and-sweep stopping the whole program.

1. There is no guard against adding it to something outside the function scope (like a tlist field in the class)

There we just have to be smart


2. The allocation will be active for the whole scope

inline var statements within the begin..end block would also be nice.

With variable available  after the var and destroyed at the next end

3. Like ansistring it needs an implicit try finally

Interfaces, too

You need a finally in most cases you uses classes, and most people are not smart and forget it

And IMHO the construct (purely using an object locally in one method) is not that common enough to warrant special syntax.



When I code in C++ I use them probably for around 80% of all variables

Everything except GUI stuff

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12857
  • FPC developer.
Re: Reference counting plz?
« Reply #19 on: March 24, 2014, 11:35:48 am »
When I code in C++ I use them probably for around 80% of all variables

Everything except GUI stuff

_References_ to C++ class or C++ classes?  Since Delphi classes are references, you have to compare them to your locally instantiated references to C++ classes in C++

karaba

  • New Member
  • *
  • Posts: 49
Re: Reference counting plz?
« Reply #20 on: March 24, 2014, 11:47:13 am »
If you need an IDE to use a language efficiently it is a bad language

Yeah that is why you are using delphi / lazarus instead of notepad and gdb directly, this one is on the same level as real programmers don't use compiler kind of crap.


You can, if they are public


LOL that is a no no if I ever seen one good thing your shares are gpled so I avoided them like the plague from the start.

On my computer:

Class method inlined: 225 ms
Fields access: 255 ms
Class method: 366 ms
Interface method: 451 ms


That means that with a refcounted non interface, the program  would run twice as fast!

Thank you for the data noted them down for fearther testing.



Not if you need to inherit from a non-interface


Look at it this way.
Code: [Select]
TMyBaseInterfacedObj = class(Tobject, IInterface);
private
  FOWner:TObject;
{
  Just copy the implementation from the TinterfacedOBject;
  just make sure that when refcount reaches 0 you call free on the aowner object instead of this object's.
}
  function ObjectRef:Tobject;//a one liner Result := self; just to be able to do TAncestor(Var.ObjectRef) simple right?
public
  constructor Create(aOwner:TObject);
end;
And you use it like this;

Code: [Select]
TmyDumclass = class(TMyStringlistOrWhatEvernonInterfaced, IInterface)
private
  FInterfaced : IInterface implements IInterface; //something along those lines you might need to make a property look it up.
public
  Constructor Create;// just add one line Finterfaced := TMyBaseInterfaceObj.Create(self); done you have an interfaced object inherited from a noninterfaced one.
end;
« Last Edit: March 24, 2014, 11:49:00 am by karaba »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12857
  • FPC developer.
Re: Reference counting plz?
« Reply #21 on: March 24, 2014, 12:25:00 pm »
Class method inlined: 225 ms
Fields access: 255 ms
Class method: 366 ms
Interface method: 451 ms

Any form of memory management will of course be slower than without.
 

BeniBela

  • Hero Member
  • *****
  • Posts: 959
    • homepage
Re: Reference counting plz?
« Reply #22 on: March 24, 2014, 01:05:25 pm »


Yeah that is why you are using delphi / lazarus instead of notepad and gdb directly, this one is on the same level as real programmers don't use compiler kind of crap.
 


No, it is about having   no redundancy in the source.

_References_ to C++ class or C++ classes?  Since Delphi classes are references, you have to compare them to your locally instantiated references to C++ classes in C++

I do not see a difference between references and actual classes, if they are both auto created/freed



LOL that is a no no

No, that is efficient


Look at it this way.

Okay, I did not know that keyword.

But does it even work?

{
  Just copy the implementation from the TinterfacedOBject;
  just make sure that when refcount reaches 0 you call free on the aowner object instead of this object's.

No copying allowed. Otherwise there is no problem with inheritance anyways.

FInterfaced : IInterface implements IInterface; //something along those lines you might need to make a property look it up.


If you use an interface type as property, you have a reference to that interface and it is never freed.

And you cannot have the  ref-counting in the parent class, because then there is no point in using implements here.


Any form of memory management will of course be slower than without.

But there is no memory management within the benchmarked loop.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Reference counting plz?
« Reply #23 on: March 24, 2014, 02:27:10 pm »
Code: [Select]
Class method inlined: 225 ms
Fields access: 255 ms
Class method: 366 ms
Interface method: 451 ms

That means that with a refcounted non interface, the program  would run twice as fast!
This is not good approach for testing.

Here you're measuring time to make a call. That's ok (for CPU level: to prove that pushing stuff to registers and the stack and then making a "call" is slower than updating registers only)
But the in the real life your body function execution takes far greater time than the function call itself.

So in the end, not using "interfaces" will NOT make a program running "twice as fast". (maybe 0.0005% increase)

Please note, that if your function execution time almost equals to the call time and the function needs to be called often (so the "call" time impacts the performance) then the implementation must be reconsidered.


My favorite example of "interfaced" applications are DirectX games. The whole DirectX API is based on Interfaces. These API calls do not impact a game performance at all.
What does impact?
- lame algorithms (of game or game-engine) <- improve developers
- huge amount of data  (typically graphics) <- improve design
- sometimes slow hardware (or its drivers) <- improve environment
But not the api call style. Please!



« Last Edit: March 24, 2014, 02:41:17 pm by skalogryz »

BeniBela

  • Hero Member
  • *****
  • Posts: 959
    • homepage
Re: Reference counting plz?
« Reply #24 on: March 24, 2014, 03:12:29 pm »
This is not good approach for testing.

Here you're measuring time to make a call. That's ok (for CPU level: to prove that pushing stuff to registers and the stack and then making a "call" is slower than updating registers only)
But the in the real life your body function execution takes far greater time than the function call itself.

So in the end, not using "interfaces" will NOT make a program running "twice as fast". (maybe 0.0005% increase)

My methods are so short:

(and I am using it in an interpreter for my programming language. So I have a lot of methods doing nothing except basic arithmetic)

(except for type/overflow checking)

My favorite example of "interfaced" applications are DirectX games. The whole DirectX API is based on Interfaces. These API calls do not impact a game performance at all.

Yet it is common wisdom that you must minimize the amount of DirectX calls


edit: I completely forgot another problem with the interfaces. They have a really strange memory layout. So a) they seem to need more memory than a corresponding class. b) You cannot see the fields of an  interface implementation in the debugger, without guessing some random offset.




Yeah that is why you are using delphi / lazarus instead of notepad and gdb directly, this one is on the same level as real programmers don't use compiler kind of crap.

But you have to use gdb directly, when the lazarus debugger does not support debugging interfaces
« Last Edit: March 24, 2014, 03:25:31 pm by BeniBela »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: Reference counting plz?
« Reply #25 on: March 24, 2014, 03:31:59 pm »
But you have to use gdb directly, when the lazarus debugger does not support debugging interfaces

Which gdb commands do you use to look at interfaces?

BeniBela

  • Hero Member
  • *****
  • Posts: 959
    • homepage
Re: Reference counting plz?
« Reply #26 on: March 24, 2014, 03:39:32 pm »

Which gdb commands do you use to look at interfaces?

None,  I am too lazy for that.

But in Lazarus I try something like TObject(pointer(intf)-8) to TObject(pointer(intf)-40) till it prints something usable, so in raw gdb, you could write a (python) macro doing that

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: Reference counting plz?
« Reply #27 on: March 24, 2014, 04:21:54 pm »
Ah yes trial and error. Maybe good for humans,  but not so good for implementation.

The debug info does not contain the offset (and the fact, that it is after the actual object, is only an implementation detail, subject to change at any time).

The only way to get the address, is to disassemble the code, find the address of the method of the interface, disassemble that (again trusting implementation detail), and there is (at least in current fpc) the offset:

Code: [Select]
WRPR_P$PROJECT1_TBAR_$_TFOO2_$_3_$_P$PROJECT1_TBAR_$__BBB
004016D0 83e814                   sub    $0x14,%eax
004016D3 e998fdffff               jmp    0x401470 <BBB>

First line adjust SELF by the offset.
2nd line jumps to implementation in object.

Only no guarantee, it will be that way in the next or any future fpc version.

Edson

  • Hero Member
  • *****
  • Posts: 1328
Re: Reference counting plz?
« Reply #28 on: March 24, 2014, 06:05:56 pm »

What you need are scoped objects. Automatically created when you enter the scope, and automatically destroyed, when you leave the scope.

E.g. something like

Code: [Select]
var foobar: scoped TStringList;
would automatically call TStringList.create, assigning it to foobar, and calling foobar.free after the end;

It would be a Wonderful improvement on the language. Of course, it needs the programmer to be responsable but it's the same for any tool.

If you need an IDE to use a language efficiently it is a bad language

IMHO it's totally TRUE.

Lazarus is a great IDE, but the language is some antique. We don't face the difficulty of write in pure Object Pascal, because we have Lazarus/Delphi for help.

I think some kind of Garbage collection would be nice for the health of FPC. It is one of the language improvements, that some people are claiming.

Lazarus 2.2.6 - FPC 3.2.2 - x86_64-win64 on Windows 10

hinst

  • Sr. Member
  • ****
  • Posts: 303
Re: Reference counting plz?
« Reply #29 on: March 24, 2014, 06:29:49 pm »
What I think could be done is to let programmer write implicit initializers/constructors and finalizers/destructors like in C++.
Code: [Select]
{
  MyObject o;   // here constructor of MyObject is called
  o.DoSomething();
}   // here destructor of MyObject is called implicitly
C++ has this feature from the very beginning
Similarly in FPC we have such kind of thing for strings.
Code: [Select]
var
  s: string;
begin
  s := 'LAWL';
end;   // here destructor of s is called implicitly
So I somehow think that it would be logical to generalize this approach further and make implicit destructors for object type work, and I am talking here about object type in FPC since object IMO is most suitable type to make automatic or rather semi-automatic memory management work; the object will be just a "smart" link or reference to actual class instance stored in heap
Code: [Select]
var
  o: TShared<TStrings>;   // constructor of TShared is called implicitly
begin
  o.Value.Add('LAWL');
end;  // destructor of o of type TShared is called implicitly;
      // since o variable was not assigned to any other variables, TShared releases underlying TStrings instance.
This would be a C++ - like approach

Everyone would then be able to customize memory management system as desired, or just stick with the traditional one; this would not affect existing libraries at all
« Last Edit: March 24, 2014, 06:37:16 pm by hinst »
Too late to escape fate

 

TinyPortal © 2005-2018