Reference counting plz? lazarus / 8-Other ---------------------------------------------------------------------- hinst · 2013-10-02 15:26 Anyone else thought about this? Why is it: long ago reference counting was implemented in Delphi for strings and dynamic arrays; but not for classes, records, objects and other types??? It is like they started improving language to make development easier, but stopped halfway through. Why is it I don't have to .Free my strings and arrays, but still have to release all other variables (like TList instances) manually? Reference counting should be possible to enable manually for any user type. They should have made it in 2001 in Delphi 6. I suppose, they (developers from Borland, perhaps) didn't want to break compatibility with existing code. But today in 2013 it seems like a very wrong decision. They had means for it. Automatic reference counting was already implemented for string types, dynamic arrays and COM interfaces. But they couldn't (or didn't want to) push it to final stage and make class instances reference-counted. They could at least make it possible to enable it on demand with some compiler directive; like I said... So now we still don't have automatic memory management. This feature could make programming so much easier. And it is not hard to implement at all  Strings and dynamic arrays can do it, but everything else can't. This is just stoopid ---------------------------------------------------------------------- avra · 2013-10-02 15:47 Not exactly what you were looking for, but who knows... Follow the gc under Delphi link at this location: http://wiki.freepascal.org/garbage_collection There is a Pascal API for Boehm Garbage Collector DLL. Maybe backend for JVM is for your liking? http://wiki.freepascal.org/FPC_JVM ---------------------------------------------------------------------- marcov · 2013-10-02 16:19 Quote from: hinst on October 02, 2013, 05:26:51 pmAnyone else thought about this? Why is it: long ago reference counting was implemented in Delphi for strings and dynamic arrays; but not for classes, records, objects and other types??? If you look at the types, you'll notice they only implemented it for non nestable types that can't form cycles.  Interfaces are carefully limited to scenario's that can't form cycles (only interface references, not class references). Which means you don't need costly code to deal with cycles (just draw refcounting graphs, and add a tstringlist to class, then myclass.thestringlist.add(myclass) and work out the refcounting. Cycles are the weak spot of refcounting, and dealing with them adds limitations, since to break cycles you must either "know" a lot about the objects, or be very conservative (and thus inefficient). Worse, contrary to the string case it would have been very incompatible. Garbage collection in all its forms is a well studied subject, with plenty of resources on the internet. I urge you to study them. Quote It is like they started improving language to make development easier, but stopped halfway through. See above, they implemented what could be done without much compromises. Recently, Embarcadero has started toying with Apple (objective C /COCOA) styled ARC ref counting in their mobile offerings. QuoteWhy is it I don't have to .Free my strings and arrays, but still have to release all other variables (like TList instances) manually? Reference counting should be possible to enable manually for any user type. Why "should" this be the case? All forms of GCs have certain assumptions (e..g movability, root finding etc) that either add certain runtime costs or language design restrictions. GC is not the ultimate goal of all programming, it is merely a technique to optimize productivity in certain problem domains. Anyway, if you are not ware of the concept of reference counting leading to mutual reference cycles, I would be very careful about what Borland "should" have done and calling them "stoopid" ---------------------------------------------------------------------- hinst · 2013-10-02 16:59 Even Microsoft .NET official memory manager for C# can't handle mutual references properly; e.g if you create two objects, each containing a pointer to another one, this would "lock" them in memory, so they will never be released by garbage collector. Still this haven't stopped them from making C# language garbage-collected. Because the benefits outweigh drawbacks (like problem with mutual reference cycles). Those mutually "locked" objects can't be released automatically, but everything else can Same is true for shared pointers from C++: if two objects have shared pointers to each other, they won't get released automatically (unless programmer handles this situation; e.g assigns NULL to one of the pointers "manually"). Yet shared pointer is a very useful concept; the developers use it In other words, the fact that sometimes reference counting leads to mutual reference cycles is not a good reason not to use reference counting. C# garbage collector and C++ shared pointers have this problem too ---------------------------------------------------------------------- Edson · 2013-10-02 19:27 Well, I have felt sometimes, that it will be great if i could avoid to Create and Destroy an simple object like a TStringList. It seems to be easy for implement, of course with some limitations. On the other hand, it's admirable what Free Pascal can do now for us. I think it could be better. But it depend on us. It's good to have suggestions, but its better to have solutions. In this particular issue, I'm not sure if its appropiate to implement a garbage collector on Free Pascal. I was thinking this could be implemented as a some kind of "high level feature". Something like a pre-processor feature. ---------------------------------------------------------------------- Leledumbo · 2013-10-03 09:58 For me, some things are better with reference counting, some are not. I prefer classes to be Create-d and Free-d manually because I'm the one who knows how the program should play with its memory / time complexity. On the other hand, strings and arrays are more commonly used for quick programming and I don't want to burden myself a lot about their memory management. It's just from my experience and preference though, but I really really don't want to have a full GC in Object Pascal. ---------------------------------------------------------------------- marcov · 2013-10-03 12:31 Quote from: hinst on October 02, 2013, 06:59:36 pmEven Microsoft .NET official memory manager for C# can't handle mutual references properly; e.g if you create two objects, each containing a pointer to another one, this would "lock" them in memory, so they will never be released by garbage collector. Still this haven't stopped them from making C# language garbage-collected. They must really have wanted it then :-) Quote Because the benefits outweigh drawbacks (like problem with mutual reference cycles). Which benefits? I've seen many C# code where they assign NUL to all references in the hope to get the GC to behave :-) I don't consider the problem of manual freeing not really big or important for many usecases, and there simply disadvantages (in determinism and transparancy of memory usage) too. Specially in non-safe languages. Quote Same is true for shared pointers from C++: if two objects have shared pointers to each other, they won't get released automatically (unless programmer handles this situation; e.g assigns NULL to one of the pointers "manually"). Yet shared pointer is a very useful concept; the developers use it So all objects are refcounted in C++ nowadays? Because that is whatt you are asking.. P.s. for occasional usage for objects/classes this can be emulated with interfaces, which works already since they were introduced (since Delphi 3, august 1997) ---------------------------------------------------------------------- hinst · 2014-03-17 11:37 What if there is a way to 'hack' dynamic array data structure to make it act like referencecounted object? Not only dynamic array releases underlying memory when reference count reaches 0, but it also is capable of executing specific actions before destruction: for example, in case one had a dynamic array of strings, then dynamic array when releasing will not only release memory allocated for storing pointers to strings, but also call destructor (or rather "dereferencer") for each string. Now all I need is to find a way to make dynamic array destructor execute not string dereferencers, but my own dereferencers for my class instances which I put in array. I wonder how I could possibly make this work; find a place where pointer to destructor method is stored? perhaps something with typinfo; I don't know ---------------------------------------------------------------------- marcov · 2014-03-17 14:33 Quote from: hinst on March 17, 2014, 12:37:59 pmWhat if there is a way to 'hack' dynamic array data structure to make it act like referencecounted object? Not only dynamic array releases underlying memory when reference count reaches 0, but it also is capable of executing specific actions before destruction: for example, in case one had a dynamic array of strings, then dynamic array when releasing will not only release memory allocated for storing pointers to strings, but also call destructor (or rather "dereferencer") for each string. Now all I need is to find a way to make dynamic array destructor execute not string dereferencers, but my own dereferencers for my class instances which I put in array. I wonder how I could possibly make this work; find a place where pointer to destructor method is stored? perhaps something with typinfo; I don't know That is basically done for you in the case of interfaces.  Just have an interface that has a array (or tlist) like interface, and make it free them ---------------------------------------------------------------------- skalogryz · 2014-03-17 15:15 Objective-C didn't have **automatic** garbage collection (only manual one). GC has been added to the ObjC 2.0 for OSX (not iOS). However, I believe ObjC developers culture makes them not rely of GC at all, using "retain"/"release" methods that are using reference count in the base NSObject. (NSObject is something similar to TObject in pascal, though is not strictly the "bottom" class). So similar approach could be taken in FP implementation. Create a reference counted base class for your own need and make sure your code follows uses ref-counting method accurately. ---------------------------------------------------------------------- marcov · 2014-03-17 15:29 Quote from: skalogryz on March 17, 2014, 04:15:49 pmSo similar approach could be taken in FP implementation. Create a reference counted base class for your own need and make sure your code follows uses ref-counting method accurately. That's a system that I use in many of my apps with larger allocations, which I pool for performance and stability reasons.  The path of the main data object through the application forks only a few times. On fork I increase the ref count, and on the end of a fork I call a .release that roughly does "dec(cnt); if cnt=0 then pool.put(self):". ---------------------------------------------------------------------- hinst · 2014-03-17 15:46 Quote from: marcov on March 17, 2014, 04:29:36 pm... That's a system that I use in many of my apps with larger allocations, which I pool for performance and stability reasons.  The path of the main data object through the application forks only a few times. On fork I increase the ref count, and on the end of a fork I call a .release that roughly does "dec(cnt); if cnt=0 then pool.put(self):". 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 ---------------------------------------------------------------------- skalogryz · 2014-03-17 15:50 Quote from: hinst on March 17, 2014, 04:46:52 pmThen 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 "Retain" (increase ref counting) the object first in a thread. Do the work. "Release" the object (decrease ref counting). Thus no thread would be able to "release" the object down to count 0. Of course, ref counting (add/dec) operations should be thread-safe in this case. And a good practice, that the thread that allocated the object releases it, if possible. ---------------------------------------------------------------------- marcov · 2014-03-17 16:03 Quote from: hinst on March 17, 2014, 04:46:52 pmQuote from: marcov on March 17, 2014, 04:29:36 pm... That's a system that I use in many of my apps with larger allocations, which I pool for performance and stability reasons.  The path of the main data object through the application forks only a few times. On fork I increase the ref count, and on the end of a fork I call a .release that roughly does "dec(cnt); if cnt=0 then pool.put(self):". 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 Atomically set and test the refcount, obviously. ---------------------------------------------------------------------- BeniBela · 2014-03-23 13:33 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) cannot access fields anymoreare much slower than classes, because every method behaves like a virtual method.  Currently you cannot have ref-counted objects with normal methods!! cannot use TAncestor(var) casts anymore  (and it is not even a compile error, just crashes at run time) 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). 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; ---------------------------------------------------------------------- marcov · 2014-03-23 19:53 Quote from: hinst on March 17, 2014, 04:46:52 pmThen 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 · 2014-03-24 04:39 Quote from: BeniBela on March 23, 2014, 02:33:34 pmI 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. Quote from: BeniBela on March 23, 2014, 02:33:34 pmcannot access fields anymoreerm doesn't compute really you couldn't access them outside the class anyway. Quote from: BeniBela on March 23, 2014, 02:33:34 pmare 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. Quote from: BeniBela on March 23, 2014, 02:33:34 pmcannot 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. Quote from: BeniBela on March 23, 2014, 02:33:34 pm 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. Quote from: BeniBela on March 23, 2014, 02:33:34 pm 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 · 2014-03-24 08:37 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 · 2014-03-24 10:26 Quote from: karaba on March 24, 2014, 05:39:35 amspace 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 Quote from: karaba on March 24, 2014, 05:39:35 amerm doesn't compute really you couldn't access them outside the class anyway. You can, if they are public Quote from: karaba on March 24, 2014, 05:39:35 am 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. Quote from: karaba on March 24, 2014, 05:39:35 amerm as long as the var is a  class Yes, that's why I want it to be a class Quote from: karaba on March 24, 2014, 05:39:35 amyes you can if it is an interface yeah that doesn't work. Exactly Quote from: karaba on March 24, 2014, 05:39:35 amtrue 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 Quote from: karaba on March 24, 2014, 05:39:35 amwell 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. Quote from: marcov on March 24, 2014, 09:37:12 am1. 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 Quote from: marcov on March 24, 2014, 09:37:12 am2. 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 Quote from: marcov on March 24, 2014, 09:37:12 am3. 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 Quote from: marcov on March 24, 2014, 09:37:12 amAnd 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 · 2014-03-24 10:35 Quote from: BeniBela on March 24, 2014, 11:26:59 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 · 2014-03-24 10:47 Quote from: BeniBela on March 24, 2014, 11:26:59 amIf 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. Quote from: BeniBela on March 24, 2014, 11:26:59 am 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. Quote from: BeniBela on March 24, 2014, 11:26:59 amOn 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. Quote from: BeniBela on March 24, 2014, 11:26:59 am 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; ---------------------------------------------------------------------- marcov · 2014-03-24 11:25 Quote from: BeniBela on March 24, 2014, 11:26:59 am 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 · 2014-03-24 12:05 Quote from: karaba on March 24, 2014, 11:47:13 am 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. Quote from: marcov on March 24, 2014, 11:35:48 am_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 Quote from: karaba on March 24, 2014, 11:47:13 amLOL that is a no no No, that is efficient Quote from: karaba on March 24, 2014, 11:47:13 amLook at it this way. Okay, I did not know that keyword. But does it even work? Quote from: karaba on March 24, 2014, 11:47:13 am{   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. Quote from: karaba on March 24, 2014, 11:47:13 amFInterfaced : 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. Quote from: marcov on March 24, 2014, 12:25:00 pm Any form of memory management will of course be slower than without. But there is no memory management within the benchmarked loop. ---------------------------------------------------------------------- skalogryz · 2014-03-24 13:27 Quote from: BeniBela on March 24, 2014, 11:26:59 amCode: [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! ---------------------------------------------------------------------- BeniBela · 2014-03-24 14:12 Quote from: skalogryz on March 24, 2014, 02:27:10 pmThis 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: Quote from: BeniBela on March 24, 2014, 11:26:59 am(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) Quote from: skalogryz on March 24, 2014, 02:27:10 pmMy 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. Quote from: karaba on March 24, 2014, 11:47:13 am 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 ---------------------------------------------------------------------- Martin_fr · 2014-03-24 14:31 Quote from: BeniBela on March 24, 2014, 03:12:29 pmBut 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 · 2014-03-24 14:39 Quote from: Martin_fr on March 24, 2014, 03:31:59 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 · 2014-03-24 15:21 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 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 · 2014-03-24 17:05 Quote from: BeniBela on March 23, 2014, 02:33:34 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. Quote from: BeniBela on March 24, 2014, 11:26:59 amIf 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. ---------------------------------------------------------------------- hinst · 2014-03-24 17:29 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;   // 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 ---------------------------------------------------------------------- karaba · 2014-03-24 23:19 Quote from: BeniBela on March 24, 2014, 01:05:25 pmQuote from: karaba on March 24, 2014, 11:47:13 amYeah 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. Interfaces are a language agnostic construct they are designed for maximum freedom and cooperation. If you can do a better job do point us on the relevant article. Quote from: BeniBela on March 24, 2014, 01:05:25 pmNo, that is efficient no that is insecure and thread unsafe, efficiency has nothing to do with public variables. Quote from: BeniBela on March 24, 2014, 01:05:25 pmQuote from: karaba on March 24, 2014, 11:47:13 amLook at it this way. Okay, I did not know that keyword. But does it even work? Sure it does I already have it working somewhere a few years back I need to find it to make sure and that's not going to happen for a forum post. Quote from: BeniBela on March 24, 2014, 01:05:25 pm Quote from: karaba on March 24, 2014, 11:47:13 am{   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. read again, you need to rewrite the IUnknown implementation adding the changes I pointed once. Quote from: BeniBela on March 24, 2014, 01:05:25 pm Quote from: karaba on March 24, 2014, 11:47:13 amFInterfaced : 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. I never said to place the ref counting on the owner I just said to call the owners destroy/free instead of the implementing object's free/destroy. If you want me to work out the implementation details for you I'm open for hire. ---------------------------------------------------------------------- BeniBela · 2014-03-25 10:36 Quote from: karaba on March 25, 2014, 12:19:57 amInterfaces are a language agnostic construct they are designed for maximum freedom and cooperation. Yes, they are. That why it is such a horrible idea to use them   for reference counting within a single language. Quote from: karaba on March 25, 2014, 12:19:57 amno that is insecure and thread unsafe, Just as thread unsafe as most normal methods. But more reliable. Because you can  that it is not thread safe when reading the source. Quote from: karaba on March 25, 2014, 12:19:57 am efficiency has nothing to do with public variables. If you look at the benchmark, they are faster than everything except inlined methods. (and with with they should be equal) And most important, they need less source, so they are more efficient to write and maintain. And need less memory Quote from: karaba on March 25, 2014, 12:19:57 amread again, you need to rewrite the IUnknown implementation adding the changes I pointed once. read again, in the very first post I said, inheritance with interfaces and non-interfaces does not work, if you use the default IUnknown implementation, instead writing your own . You should not need to reimplement basic language features Quote from: karaba on March 25, 2014, 12:19:57 amI never said to place the ref counting on the owner I just said to call the owners destroy/free instead of the implementing object's free/destroy. But I said, I thought, you must place it in the owner. If you place it in the child, the count never becomes 0, because the owner has a reference to the child. Well, perhaps with a casting getter Quote from: karaba on March 25, 2014, 12:19:57 amIf you want me to work out the implementation details for you I'm open for hire. Okay As payment you get a free benchmark source (see above) ---------------------------------------------------------------------- karaba · 2014-03-25 12:23 Quote from: BeniBela on March 25, 2014, 11:36:49 amQuote from: karaba on March 25, 2014, 12:19:57 amInterfaces are a language agnostic construct they are designed for maximum freedom and cooperation. Yes, they are. That why it is such a horrible idea to use them   for reference counting within a single language. Since you haven't provided any kind of documentation on how you think that is suppose to work with out the virtual methods for the inheritance's  sake I have no reason to believe that it is doable with out "copying" even if it was supported on the level you want it to. Quote from: BeniBela on March 25, 2014, 11:36:49 amQuote from: karaba on March 25, 2014, 12:19:57 amno that is insecure and thread unsafe, Just as thread unsafe as most normal methods. But more reliable. Because you can  that it is not thread safe when reading the source. Quote from: karaba on March 25, 2014, 12:19:57 am efficiency has nothing to do with public variables. If you look at the benchmark, they are faster than everything except inlined methods. (and with with they should be equal) And most important, they need less source, so they are more efficient to write and maintain. And need less memory Depends heavily on how you are used to work but yes it can be seen as a plus in this case it means that the programmer has a lot to learn before he/she is allowed to touch any commercial code for anything more than debugging. I can't see any sane design that requires the fields to be public just for efficiency's sake(sacrificing security and power). It is a well known fact that having setter and getter methods will be slower that doesn't really mean that the final result will be slower though. Quote from: BeniBela on March 25, 2014, 11:36:49 am Quote from: karaba on March 25, 2014, 12:19:57 amread again, you need to rewrite the IUnknown implementation adding the changes I pointed once. read again, in the very first post I said, inheritance with interfaces and non-interfaces does not work, if you use the default IUnknown implementation, instead writing your own . You should not need to reimplement basic language features not a basic language feature, can't be considered a basic feature, although it has become an expected one in all the modern languages ee .NET objective C and even the new delphi compiler uses it, it is still a pure mans garbage collector in my book (it is used as one any way). Quote from: BeniBela on March 25, 2014, 11:36:49 amQuote from: karaba on March 25, 2014, 12:19:57 amI never said to place the ref counting on the owner I just said to call the owners destroy/free instead of the implementing object's free/destroy. But I said, I thought, you must place it in the owner. If you place it in the child, the count never becomes 0, because the owner has a reference to the child. Well, perhaps with a casting getter Hopefully "with a casting getter" you are talking about a property's getter method that will return an interface, keeping the field variable as a class, instead of being an interface it self, in which case yeah that will do it but you could also free on 1, why would that require to put the ref counting on the owner it self? Quote from: BeniBela on March 25, 2014, 11:36:49 amQuote from: karaba on March 25, 2014, 12:19:57 amIf you want me to work out the implementation details for you I'm open for hire. Okay As payment you get a free benchmark source (see above) it seems highly biased and based on what it looks like a bad design sorry but that wouldn't do. To tell you the truth I'm not against a faster way to add reference counting to a class although I don't think we will earn anything else than less typing. In both cases there is the need to support a different action when the counter reaches 0 (putting it on a pool instead of freeing it for example) and that is the developer's obligation to provide. ---------------------------------------------------------------------- BeniBela · 2014-03-25 15:22 Quote from: karaba on March 25, 2014, 01:23:34 pmSince you haven't provided any kind of documentation on how you think that is suppose to work with out the virtual methods for the inheritance's  sake I have no reason to believe that it is doable with out "copying" even if it was supported on the level you want it to. You do not need virtual methods for reference counting. Here is documentation: http://docwiki.embarcadero.com/RADStudio/XE5/en/Automatic_Reference_Co unting_in_Delphi_Mobile_Compilers But I do not want inheritance, I just want a normal class with reference counting! Quote from: karaba on March 25, 2014, 01:23:34 pmI can't see any sane design that requires the fields to be public just for efficiency's sake(sacrificing security and power). It is the same desig, where they are not public. Just with less typing Quote from: karaba on March 25, 2014, 01:23:34 pmIt is a well known fact that having setter and getter methods will be slower that doesn't really mean that the final result will be slower though. The issue is not that they make the program slower, but that it is a waste of time to write them. Quote from: karaba on March 25, 2014, 01:23:34 pm not a basic language feature, can't be considered a basic feature, although it has become an expected one in all the modern languages ee .NET objective C and even the new delphi compiler uses it, it is still a pure mans garbage collector in my book (it is used as one any way). Well, nowadays it is. And what does not adapt, dies out Quote from: karaba on March 25, 2014, 01:23:34 pmHopefully "with a casting getter" you are talking about a property's getter method that will return an interface, keeping the field variable as a class, instead of being an interface it self, in which case yeah that will do it yes Quote from: karaba on March 25, 2014, 01:23:34 pm why would that require to put the ref counting on the owner it self? it does not I wrote that before I thought of a getter (because when I looked in the documentation, it said you could have a class as implements property, which seems like the ideal solution, but than the bugtracker said that is not supported in fpc) Quote from: BeniBela on March 25, 2014, 11:36:49 amthan less typing. That is the most important goal of a programming language! Quote from: BeniBela on March 25, 2014, 11:36:49 amwhen the counter reaches 0 (putting it on a pool instead of freeing it for example) and that is the developer's obligation to provide. Perhaps overriding the destructor is sufficient ---------------------------------------------------------------------- howardpc · 2014-03-25 16:36 Quote from: BeniBela on March 25, 2014, 04:22:17 pm Quote from: BeniBela on March 25, 2014, 11:36:49 amthan less typing. That is the most important goal of a programming language! It might be one of the goals of a terser language such as C, but it has never been a goal of Object Pascal, which is widely regarded as a verbose language, deliberately designed that way to be readable and readily comprehensible. It's true that FPC allows a few C-like abbreviated operators such as +=, but I would say that the principle of adopting language changes simply because they reduce the amount you have to type is against the spirit of Pascal. That is what a good editor and IDE is designed for, not a guiding principle when proposing changes to the language. Otherwise relatively recent (and rather long) keywords such as "initialization" and "resourcestring" would have been rejected rather than being introduced, because it is not beyond the wit of man to come up with shorter (albeit less self-explanatory, and less readable) alternatives. ---------------------------------------------------------------------- BeniBela · 2014-03-25 17:02 Quote from: howardpc on March 25, 2014, 05:36:36 pm It might be one of the goals of a terser language such as C, but it has never been a goal of Object Pascal, which is widely regarded as a verbose language, deliberately designed that way to be readable and readily comprehensible. It's true that FPC allows a few C-like abbreviated operators such as +=, but I would say that the principle of adopting language changes simply because they reduce the amount you have to type is against the spirit of Pascal. That is what a good editor and IDE is designed for, not a guiding principle when proposing changes to the language. Otherwise relatively recent (and rather long) keywords such as "initialization" and "resourcestring" would have been rejected rather than being introduced, because it is not beyond the wit of man to come up with shorter (albeit less self-explanatory, and less readable) alternatives. It is also a goal of Object Pascal. At least if you count elements instead characters (once the stupid german keyboard layout it is faster to write begin than { ) initialization is only written once, and resourcestring is actually an abbreviation to reduce the amount of typing. Writing resourcestring foo = 'bar'; is far shorter than writing something var foo: string; foo := getRessource().getString("foo") in the program and additionally foo=bar in a ressource. Quote from: howardpc on March 25, 2014, 05:36:36 pmdeliberately designed that way to be readable and readily comprehensible. writable and readable is the same The less you need to write, the less someone else needs to read ---------------------------------------------------------------------- hinst · 2014-03-25 17:10 So what about my suggestion? What about reference counting? Any chance it will be implemented, but not with COM interfaces? The problem with interfaces is that there are no "just interfaces" in FreePascal, there are only COM interfaces and CORBA interfaces, the latter are not reference-counted Therefore I imply that COM interfaces do indeed add overhead to program, don't they? ---------------------------------------------------------------------- irfanbagus · 2014-03-25 17:24 Quote from: BeniBela on March 25, 2014, 06:02:22 pmwritable and readable is the same The less you need to write, the less someone else needs to read it is not. an extreme example is brainfuck. readability is about how easy a program to understand, not how easy to read. ---------------------------------------------------------------------- BeniBela · 2014-03-25 17:31 Quote from: irfanbagus on March 25, 2014, 06:24:06 pmit is not. an extreme example is brainfuck. readability is about how easy a program to understand, not how easy to read. And how long do you think you need to write something there? When a simple expression like 123 becomes ++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++ Brainfuck is an example for a completely unwritable language, so of course it is completely unreadable as well ---------------------------------------------------------------------- hinst · 2014-03-25 18:19 People we need means for automatic memory management, you have to agree with me at least on this. C++ provides language constructs necessary for automatic memory management by means of reference counting, but FreePascal provides only COM interfaces for this (like I said, there is actually no "just interface" type, only COM interface) Now we just need something like COM interface, but without the COM part ---------------------------------------------------------------------- skalogryz · 2014-03-25 19:18 Quote from: hinst on March 25, 2014, 07:19:30 pmPeople we need means for automatic memory management, you have to agree with me at least on this. C++ provides language constructs necessary for automatic memory management by means of reference counting, but FreePascal provides only COM interfaces for this (like I said, there is actually no "just interface" type, only COM interface) Now we just need something like COM interface, but without the COM part Are you talking about this? Because C++ samples you have shown earlier are not reference counting at all. ---------------------------------------------------------------------- hinst · 2014-03-25 19:42 Quote from: skalogryz on March 25, 2014, 08:18:42 pmAre you talking about this? Because C++ samples you have shown earlier are not reference counting at all. One could implement refcounted objects in C++ long before C++11 standard appeared C++ provides important features for this task: 1. C++ calls user-defined constructor for any non-pointer variable as soon as it is declared 2. When overloading assignment operator, one can access variable on the left side. 3. C++ calls user-defined destructor for any non-pointer variable as soon as it goes out of scope. FreePascal lacks all three of these features One could possibly implement refcounting system for FreePascal either using COM interfaces or doing all the hard work manually by inserting required calls by himself Boost library for C++ has shared pointer class, Qt library has shared pointer class, neither of these classes were dependent on C++11 ---------------------------------------------------------------------- karaba · 2014-03-25 22:39 Quote from: BeniBela on March 25, 2014, 04:22:17 pmYou do not need virtual methods for reference counting. Here is documentation: http://docwiki.embarcadero.com/RADStudio/XE5/en/Automatic_Reference_Co unting_in_Delphi_Mobile_Compilers But I do not want inheritance, I just want a normal class with reference counting! Yeah you took the worst case and made it a requirement? The link above refers to a design where all classes regardless of depth of hierarchy are reference counted and you as a developer have no control over its functionality not to mention over its existence. That might make a language modern hip or what ever is "in" this days but it makes it less powerful as well it takes power out of the developers hands asking you adapt this is the reason why those modern languages are not used for system development (drivers kernel etc) directly. I'm all for making a language easier to use but I'm against sacrificing power in that altar truthfully I prefer to not add reference counting and add the ability to write kernel drivers-code. Quote from: BeniBela on March 25, 2014, 04:22:17 pm It is the same desig, where they are not public. Just with less typing The issue is not that they make the program slower, but that it is a waste of time to write them. it is time for you to discover Shift+Ctrl+C, you might be able to avoid even more typing. Quote from: BeniBela on March 25, 2014, 04:22:17 pm[snip] .. well the fact is that you can add ref counting to any class you want regardless of inheritance with 2 code lines. The implementation details are outside the scope of this thread. Quote from: BeniBela on March 25, 2014, 11:36:49 am Quote from: karaba on March 25, 2014, 01:23:34 pmthan less typing. That is the most important goal of a programming language! In that case I recommend you use C/C++ it has less typing than pascal on all levels. Quote from: BeniBela on March 25, 2014, 11:36:49 amQuote from: karaba on March 25, 2014, 01:23:34 pmwhen the counter reaches 0 (putting it on a pool instead of freeing it for example) and that is the developer's obligation to provide. Perhaps overriding the destructor is sufficient Sorry to late, when the destructor is called it is impossible to stop the memory clean up of the object's memory and releasing it back to the memory manager. ---------------------------------------------------------------------- BeniBela · 2014-03-25 23:05 Quote from: karaba on March 25, 2014, 11:39:41 pmYeah you took the worst case and made it a requirement? Are you even reading my posts? I said I want a keyword that makes an ordinary class ref-counted. That would be pointless, if all classes are ref-counted. But it shows you can have ref-counted classes not based on interfaces. Quote from: karaba on March 25, 2014, 11:39:41 pmit is time for you to discover Shift+Ctrl+C, you might be able to avoid even more typing. And that I want to be able to use a language without an IDE Besides, here that always puts all methods in the wrong place Quote from: karaba on March 25, 2014, 11:39:41 pmIn that case I recommend you use C/C++ it has less typing than pascal on all levels. It does not. Soon you need a pimpl pattern and declare every method twice, which is just as bad as having an interface And it compiles too slowly. All the time saved on writing is spend tenfolds waiting on the compiler Quote from: karaba on March 25, 2014, 11:39:41 pmSorry to late, when the destructor is called it is impossible to stop the memory clean up of the object's memory and releasing it back to the memory manager. Not if you also override FreeInstance ---------------------------------------------------------------------- karaba · 2014-03-26 00:21 Quote from: BeniBela on March 26, 2014, 12:05:44 am Quote from: karaba on March 25, 2014, 11:39:41 pmYeah you took the worst case and made it a requirement? Are you even reading my posts? I said I want a keyword that makes an ordinary class ref-counted. That would be pointless, if all classes are ref-counted. But it shows you can have ref-counted classes not based on interfaces. It was never a question of "if" you can have a ref counted class or not our discussion is based on having ref counting not based on inheritance and not copying the code to each implementation at least it started like that. Quote from: BeniBela on March 26, 2014, 12:05:44 am Quote from: karaba on March 25, 2014, 11:39:41 pmit is time for you to discover Shift+Ctrl+C, you might be able to avoid even more typing. And that I want to be able to use a language without an IDE Besides, here that always puts all methods in the wrong place I don't know what you mean by wrong place and truthfuly I never had any problem on where the methods are placed in implementation I always jump to them from the interface part so the interface and only the interface must be in correct order, so even if you are right it will never have any meaning for me. as for your unhealthy obsession with the IDEs (or the ability to work with out them to be precise) it makes me think of the nomadic way of life use the absolutely minimum that you can curry with you at all times, no skyscrapers or concrete houses, a waste of time and effort in my book I wouldn't go back to notepad for code editing not with all the wonders the IDEs have to offer that make me even lazier. Quote from: BeniBela on March 26, 2014, 12:05:44 amQuote from: karaba on March 25, 2014, 11:39:41 pmIn that case I recommend you use C/C++ it has less typing than pascal on all levels. It does not. Soon you need a pimpl pattern and declare every method twice, which is just as bad as having an interface And it compiles too slowly. All the time saved on writing is spend tenfolds waiting on the compiler My point exactly, less typing is not the defining feature of a modern language, there are to many things that need to be taken in to consideration. Quote from: BeniBela on March 26, 2014, 12:05:44 am Quote from: karaba on March 25, 2014, 11:39:41 pmSorry to late, when the destructor is called it is impossible to stop the memory clean up of the object's memory and releasing it back to the memory manager. Not if you also override FreeInstance I always stayed away from those methods so I can't say if it would be of any help but it seems it would be equal to the free mess of the new delphi compiler. I avoid redefining the existing methods at all cost when free is called then I expect an object to be freed everything else makes the framework hard to work with so for me is a no go from the start. I would redesign the classes to avoid the call to free or even avoid using the reference counting all together if I couldn't make it work my way. ---------------------------------------------------------------------- marcov · 2014-03-26 09:51 Quote from: hinst on March 25, 2014, 07:19:30 pmPeople we need means for automatic memory management, you have to agree with me at least on this. No, I don't, specially in the context of an existing language with backwards compat requirements like FPC/Delphi. This because the better performing forms of automatic management are already not possible, since they need to be designed in from the start. And manual is often better than a kludge as automatic memory management. QuoteC++ provides language constructs necessary for automatic memory management by means of reference counting, but FreePascal provides only COM interfaces for this (like I said, there is actually no "just interface" type, only COM interface) I don't know those newer C++ constructs (smartptrs) on an internal level that well. The question is also what they are meant for. QuoteNow we just need something like COM interface, but without the COM part There are non COM interfaces, but the trouble is that the COM part *is* the reference counting :-) ---------------------------------------------------------------------- marcov · 2014-03-26 09:54 Quote from: hinst on March 25, 2014, 08:42:48 pmOne could implement refcounted objects in C++ long before C++11 standard appeared C++ provides important features for this task: 1. C++ calls user-defined constructor for any non-pointer variable as soon as it is declared 2. When overloading assignment operator, one can access variable on the left side. 3. C++ calls user-defined destructor for any non-pointer variable as soon as it goes out of scope. FreePascal lacks all three of these features But implicit constructors also have problems, relating to multiple constructors and their overloading, the fact that Delphi constructors are two step etc. Yes, you can try to build a C++ object model from scratch on top of structs, but that is something else then adding automatic memory management to FPC. Anyway, for me this is the end of the discussion, since it is turning in to a yes-no discussion. I'll wait what final proposal you guys come up with, so that we have something to really comment on. (see http://www.freepascal.org/faq.var#extensionselect  with details about what such proposal must cover) ---------------------------------------------------------------------- BeniBela · 2014-03-26 10:28 Quote from: karaba on March 26, 2014, 01:21:01 amon having ref counting not based on inheritance and not copying the code to each implementation at least it started like that. It started with having ref counting not based on interfaces. Which is similar to Delphi's implementation. Quote from: karaba on March 26, 2014, 01:21:01 amI don't know what you mean by wrong place and truthfuly I never had any problem on where the methods are placed in implementation I always jump to them from the interface part so the interface and only the interface must be in correct order, so even if you are right it will never have any meaning for me. interface: private instead protected, or the wrong private section, if there are multiple; implementation: in the pas file, instead the inc file. Quote from: karaba on March 26, 2014, 01:21:01 amas for your unhealthy obsession with the IDEs (or the ability to work with out them to be precise) it makes me think of the nomadic way of life use the absolutely minimum that you can curry with you at all times, no skyscrapers or concrete houses, a waste of time and effort in my book I wouldn't go back to notepad for code editing not with all the wonders the IDEs have to offer that make me even lazier. If I write in my own programming language without an IDE (because there exists no IDE) the programming goes faster than in Pascal with IDE. Quote from: marcov on March 26, 2014, 10:54:26 amAnyway, for me this is the end of the discussion, since it is turning in to a yes-no discussion. We should make a forum thread with a poll Quote from: marcov on March 26, 2014, 10:54:26 amI'll wait what final proposal you guys come up with, so that we have something to really comment on. This issue is dicussed every year. There it would be strange, if no one has made a proposal so far. And the goal is obvious anyways. It would be pointless to make a detailed proposal, if it just gets rejected again ---------------------------------------------------------------------- BigChimp · 2014-03-26 10:59 Quote from: BeniBela on March 26, 2014, 11:28:47 amQuote from: marcov on March 26, 2014, 10:54:26 amAnyway, for me this is the end of the discussion, since it is turning in to a yes-no discussion. We should make a forum thread with a poll No, people who want to implement this should start writing the implementation. Talk is cheap. Quote from: BeniBela on March 26, 2014, 11:28:47 amQuote from: marcov on March 26, 2014, 10:54:26 amI'll wait what final proposal you guys come up with, so that we have something to really comment on. This issue is dicussed every year. There it would be strange, if no one has made a proposal so far. And the goal is obvious anyways. It would be pointless to make a detailed proposal, if it just gets rejected again Talk is cheap. You can't really force volunteers to do what you want if they don't agree. Some people do not seem to get this. So why not fork FPC, prove your version works better and then get the FPC devs to accept your changes once it turns out your version is superior (or lose their devs)? Perhaps you can join forces with Martin Schreiber - AFAIR he's writing his own RTL etc already. ---------------------------------------------------------------------- BeniBela · 2014-03-26 11:31 Quote from: BigChimp on March 26, 2014, 11:59:11 am No, people who want to implement this should start writing the implementation. Talk is cheap. I could probably write an patch as fast as I could write a proposal. But without people supporting that feature, it is pointless, because no one would use it. Quote from: BigChimp on March 26, 2014, 11:59:11 amSo why not fork FPC, prove your version works better and then get the FPC devs to accept your changes once it turns out your version is superior (or lose their devs)? Too much trouble Last time I forked a project to add some missing features, the original author was so annoyed that he hired a  lawyer to sue sourceforge. and now every other bug report he cannot reproduce  is answered with "invalid, you neo-nazi zealot of " Quote from: BigChimp on March 26, 2014, 11:59:11 amPerhaps you can join forces with Martin Schreiber - AFAIR he's writing his own RTL etc already. He is doing the opposite in MSElang. Removing features to get a more pure Pascal. No interfaces, no records, no generics, no operator overloading ... It is a completely braindead project ---------------------------------------------------------------------- BigChimp · 2014-03-26 11:43 Thanks for that clear response. Too bad about the sourceforge guy... Well, as we've exhausted: - you doing the work - the fpc devs doing the work (assuming there will be no proposal that will be accepted) that leaves: - somebody else doing the work - stopping the discussion as pointless and waiting for it to flare again in a couple of months with perhaps different players - keep discussing this I know what I'll put my money on... Cynical? Me? Never. ---------------------------------------------------------------------- hinst · 2014-03-26 12:09 my proposition is really simple: introduce some compiler switch like {$RefC On} then call _AddRef & _Release methods for all variables of type which was declared in a unit with {$RefC On} like Code: [Select]unit RefC; {$RefC On} interface type   TSharedPointer = object     function _AddRef: Integer;     function _Release: Integer;   end; ... That's it. What I don't like about manual reference counting is that if I forget to call _Release, then I'm doomed; if I call _AddRef twice, for example before assignment, and then also in a property getter or setter, then I'm doomed as well. It is really easy to insert _AddRef or _Release call in a wrong place, or to forget to insert one. Especially in complex expressions like A := B + C * D; where (C * D) will never be released ---------------------------------------------------------------------- mse · 2014-03-26 13:58 Quote from: BeniBela on March 26, 2014, 12:31:24 pm He is doing the opposite in MSElang. Removing features to get a more pure Pascal. No interfaces, no records, no generics, no operator overloading ... It is a completely braindead project This is not correct. MSElang has interfaces. Records, objects and classes are unified into a single concept, MSElang will have operator overloading if there is a solution for fast compiling. I am confident that I will find such a solution. ;-) MSElang will not provide generics that is true. It is not necessary because of other MSElang features. ---------------------------------------------------------------------- Edson · 2014-03-26 16:02 Quote from: hinst on March 25, 2014, 07:19:30 pmPeople we need means for automatic memory management, you have to agree with me at least on this. I agree. Quote from: karaba on March 26, 2014, 01:21:01 amas for your unhealthy obsession with the IDEs (or the ability to work with out them to be precise) it makes me think of the nomadic way of life use the absolutely minimum that you can curry with you at all times, no skyscrapers or concrete houses, a waste of time and effort in my book I wouldn't go back to notepad for code editing not with all the wonders the IDEs have to offer that make me even lazier. Having a powerful IDE, is not going to correct the language faults. Quote from: mse on March 26, 2014, 02:58:49 pmRecords, objects and classes are unified into a single concept,   Good point. It's what I was thinking about. ---------------------------------------------------------------------- hinst · 2014-04-02 14:20 when I do manual reference counting I often get a memory leak, and then I am like "Where did I forget to call release method?" and then I search search search    until I finally find it and realize how stupid I am And other times I get an Access Violation, and then I am like "Where did I release object twice? Or maybe I forgot to add ref?" and then I search search search    those cases are even more difficult to detect ---------------------------------------------------------------------- Martin_fr · 2014-04-02 14:25 LazUTils has a TRefCounted object, for manual refcounting. And it can be compiled with a debug define, allowing each Add/Releas- Ref pair to be given a unique ID. So you will see which ref calls twice., And it could be easily added, that in debug mode all objects a kept in a list, so you can find out, which object is hold by which ID. --- And btw, many automatic recounting solutions, will also lead to leaks, if there are circles. ---------------------------------------------------------------------- karaba · 2014-04-02 14:57 Quote from: Edson on March 26, 2014, 05:02:05 pm Quote from: karaba on March 26, 2014, 01:21:01 amas for your unhealthy obsession with the IDEs (or the ability to work with out them to be precise) it makes me think of the nomadic way of life use the absolutely minimum that you can curry with you at all times, no skyscrapers or concrete houses, a waste of time and effort in my book I wouldn't go back to notepad for code editing not with all the wonders the IDEs have to offer that make me even lazier. Having a powerful IDE, is not going to correct the language faults. Having a powerful language will not help the developer discover its rtl or other libraries. I do not see (what you describe as) a fault in the current language I do see a lot of problems on the auto memory managed ones that do not exists on the non managed but this is something not suited for conversation since I'm on the "I do not care enough to vote against/for it" camp, as long as I can opt out of it feel free to add what ever you want need. ---------------------------------------------------------------------- BeniBela · 2014-04-03 12:43 Manual reference counting is annoying, if you want to use exceptions. Far too many code paths too consider ---------------------------------------------------------------------- karaba · 2014-04-03 13:13 Quote from: BeniBela on April 03, 2014, 02:43:26 pmManual reference counting is annoying, if you want to use exceptions. Far too many code paths too consider can you give me an example so far I was under the impression that the compiler would apply a blanket statement something along the lines of codeblock begin // insert all the addref here. try // user code here. finally   //release all the ref here. end; codeblock end; Am I wrong on my assumptions? ---------------------------------------------------------------------- BeniBela · 2014-04-03 14:03 Quote from: karaba on April 03, 2014, 03:13:27 pmcan you give me an example An example for what? Quote from: karaba on April 03, 2014, 03:13:27 pmso far I was under the impression that the compiler would apply a blanket statement something along the lines of Perhaps for automatical reference counting. For manual it does not do anything Quote from: karaba on April 03, 2014, 03:13:27 pm// insert all the addref here. That has to be within the user code, where the value is created ---------------------------------------------------------------------- Martin_fr · 2014-04-03 14:25 Someone was talking about doing ref count by hand, and what problems he had. So I gave him some info, that may (on may not) be useful. Yes, if there was automatic ref counting the compiler would do hidden try except for that. It does currently do so for strings and dyn array. But we do not have automatic ref count. It was already pointed out what the steps are to volunteer for doing it: http://forum.lazarus.freepascal.org/index.php/topic,22231.msg144318.ht ml#msg144318 http://www.freepascal.org/faq.var#extensionselect So, if you want it, go ahead. Follow the steps, do a proposal, get an agreement on the requirements,  and implement it. ---------------------------------------------------------------------- marcov · 2014-04-03 23:35 Quote from: Martin_fr on April 03, 2014, 04:25:31 pmSomeone was talking about doing ref count by hand, and what problems he had. So I gave him some info, that may (on may not) be useful. Yes, if there was automatic ref counting the compiler would do hidden try except for that. It does currently do so for strings and dyn array. (and interfaces) ---------------------------------------------------------------------- BeniBela · 2014-04-05 16:40 Quote from: Martin_fr on April 03, 2014, 04:25:31 pmSomeone was talking about doing ref count by hand, and what problems he had. So I gave him some info, that may (on may not) be useful. Well that was completely useless I doubt that "someone" wanted advice, he was just complaining that his proposed "proposition" was being ignored ---------------------------------------------------------------------- Martin_fr · 2014-04-05 17:41 @BeniBela: useless for you, well indeed (since you say so). "completely useless": I wonder how you come to this judgement, and how you know that this applies to *all* other past and future readers of my post? I wonder even, if you had confirmation or any form of secured knowledge af the usefulness to the one person who wrote about ref by hand first? But even, if that person would find it useless, this is a public forum, information is always for all readers, so once the topic was up, there are many readers and still will be more in the future. You have some magic power, so you know it will be useless to them all? If I had not known, it would have been useful to me. Yes that is right: Even if there was fully automated refcounting, I would prefer refcounting by hand. That leaves the control of how it works with me. And that is what I prefer. Who are you to say there is no one else who might see things that way? ---------------------------------------------------------------------- Martin_fr · 2014-04-05 17:55 Quote from: BeniBela on April 05, 2014, 06:40:43 pm he was just complaining that his proposed "proposition" was being ignored Maybe, but that would be strange. Since the answer was given before, with reference on how to make a proposal, and the need to find a volunteer. ---------------------------------------------------------------------- hinst · 2014-04-05 18:01 Whoa whoa. Let's solve problems, not create them. Peace plz. I would not argue with site admin unless I want to get banned and go ask my mom programming-related questions  I do not want to implement features for FPC myself, and even if I wanted to, I am not sure if I could. Perhaps the best thing to do is to stick with existing compiler features and achieve goals using those existing features, not dream about new features. ---------------------------------------------------------------------- Martin_fr · 2014-04-05 19:06 Quote from: hinst on April 05, 2014, 08:01:24 pmWhoa whoa. Let's solve problems, not create them. Peace plz. I would not argue with site admin unless I want to get banned and go ask my mom programming-related questions  If I argue, I argue as user. All else would be abusive. QuoteI do not want to implement features for FPC myself, and even if I wanted to, I am not sure if I could. Perhaps the best thing to do is to stick with existing compiler features and achieve goals using those existing features, not dream about new features. Well you can always just add it as feature request, but then it still needs a volunteer. Lazarus has a wiki page for that (not sure if fpc has). Mantis may or may not be ok. IMHO Mantis is good, if there is a chance it will be done in not to far future. ---------------------------------------------------------------------- marcov · 2014-04-05 21:22 Quote from: Martin_fr on April 05, 2014, 09:06:42 pm QuoteI do not want to implement features for FPC myself, and even if I wanted to, I am not sure if I could. Perhaps the best thing to do is to stick with existing compiler features and achieve goals using those existing features, not dream about new features. Well you can always just add it as feature request, but then it still needs a volunteer. No, IMHO even a feature request needs to request something concrete and  implementable, not just "doing something with automatic memory management". That is too vague, and would probably be closed with "use interfaces" ---------------------------------------------------------------------- mse · 2014-04-06 06:56 Quote from: Martin_fr on April 05, 2014, 07:41:06 pmYes that is right: Even if there was fully automated refcounting, I would prefer refcounting by hand. That leaves the control of how it works with me. And that is what I prefer. Me too. I very well remember the nightmare with the reference counted COM interfaces for the Delphi compatible MSEgui. The FPC CORBA-style interfaces were a big simplification. ---------------------------------------------------------------------- hinst · 2014-04-17 07:34 I recently came up with a test. I wanted to find out what is performance penalty from COM interface overhead. Here is what I found: there is no overhead. I compared standard TInterfacedObject implementing IUnknown with my custom implementation of reference-counted object (which does not implement COM interface) Code: [Select]program project1; {$Interfaces COM} uses   EpikTimer,   PSHO_SharedObjectU; type   TCOM = class(TInterfacedObject)   end; procedure TestCOM(aCom: IUnknown); var   b: IUnknown; begin   b := aCom;   b := nil; end; procedure TestSha(const aSha: TSharedObject); var   b: TSharedObject; begin   b := nil;   aSha.TakeTo(@b);   b.Drop; end; var   com: IUnknown;   sha: TSharedObject;   i: Integer;   timer: TEpikTimer; begin   timer := TEpikTimer.Create(nil);   com := TCOM.Create;   timer.Clear;   timer.Start;   for i := 0 to 1000000 do     TestCOM(com);   timer.Stop;   WriteLN(timer.ElapsedStr);   sha := TSharedObject.Create;   sha.Take;   timer.Clear;   timer.Start;   for i := 0 to 1000000 do     TestSha(sha);   timer.Stop;   WriteLN(timer.ElapsedStr);   sha.Drop;   timer.Free; end. I won't post my implementation of TSharedObject because it's pretty irrelevant, and there's nothing interesting about it. What matters is: COM interface AddRef & Release 1 000 000 times takes about 50 milliseconds My custom object AddRef & Release 1 000 000 times takes about 50 milliseconds as well In terms of memory I found that each my object allocates about 88 bytes while TInterfacedObject allocates 80 bytes [even slightly better]. What I am still unsure about though is whether a object-based implementation would work faster, or at least it should allocate less memory. 80 bytes for an empty object is a bit too much ---- Worth mentioning in relation to COM interfaces: consider procedure TestCOM(aCom: IUnknown); //and procedure TestCOM(const aCom: IUnknown); It works faster with const enabled. Otherwise it works significantly slower: 70 milliseconds instead of 50 ---------------------------------------------------------------------- skalogryz · 2014-04-17 11:03 Quote from: hinst on April 17, 2014, 09:34:28 amWorth mentioning in relation to COM interfaces: consider procedure TestCOM(aCom: IUnknown); //and procedure TestCOM(const aCom: IUnknown); It works faster with const enabled. Otherwise it works significantly slower: 70 milliseconds instead of 50 This is odd. Interface is a pointer. What's happening in the assembler level? (it feels like with "const" AddRef is just not being called, assuming there would be no changes to the interface). Is it possible to increase the test time up to a second? Just to be more accurate. How about 10 M iterations, rather than 1M ? ---------------------------------------------------------------------- marcov · 2014-04-17 11:15 Quote from: hinst on April 17, 2014, 09:34:28 amI recently came up with a test. I wanted to find out what is performance penalty from COM interface overhead. On what platform did you test? ---------------------------------------------------------------------- hinst · 2014-04-17 12:01 Quote from: skalogryz on April 17, 2014, 01:03:09 pmThis is odd. Interface is a pointer. What's happening in the assembler level? (it feels like with "const" AddRef is just not being called, assuming there would be no changes to the interface). This is in fact not odd at all. Same happens with all reference counted types. For example, strings. If you have Code: [Select]procedure Go(s: string);Then the compiler will increase reference count for s when entering procedure; but if you have Code: [Select]procedure Go(const s: string);Then the compiler will not touch reference count for s. Compiler skips reference counting for const arguments. Take a look at this article plz: http://www.freepascal.org/docs-html/ref/refsu63.html . Quote from: marcov on April 17, 2014, 01:15:11 pmOn what platform did you test? I tested on Windows. If I increase iteration count to 10 M then I get   0,449796 for COM   0,359612 for my object   // seconds I have a very basic testing app; I could do a more in-depth test; but it will take some time to develop testing app. Perhaps I will do it; not sure when ---------------------------------------------------------------------- marcov · 2014-04-17 12:32 Move your test to a procedure and then do   Code: [Select]coinitialize(nil);   benchmarkproc;   couninitialize(nil); ---------------------------------------------------------------------- hinst · 2014-04-17 12:39 Quote from: marcov on April 17, 2014, 02:32:30 pmMove your test to a procedure and then do   Code: [Select]coinitialize(nil);   benchmarkproc;   couninitialize(nil); Thanks for suggestion. Tried it. Memory usage increased by 1 kilobyte. I doubt though that it got attached to com interface instance, perhaps it was allocated globally. In terms of speed, however, no difference at all. Note that I do not measure time spent on class instance construction, only assignment ---------------------------------------------------------------------- marcov · 2014-04-17 12:46 Quote from: hinst on April 17, 2014, 02:39:38 pmQuote from: marcov on April 17, 2014, 02:32:30 pmMove your test to a procedure and then do   Code: [Select]coinitialize(nil);   benchmarkproc;   couninitialize(nil); Thanks for suggestion. Tried it. Memory usage increased by 1 kilobyte. I doubt though that it got attached to com interface instance, perhaps it was allocated globally. In terms of speed, however, no difference at all. Note that I do not measure time spent on class instance construction, only assignment Thanks for testing. I just remembered that sometimes that would influence COM related issues (IIRC it is the per thread init of COM). ---------------------------------------------------------------------- skalogryz · 2014-04-17 13:24 Quote from: hinst on April 17, 2014, 02:01:21 pmThen the compiler will not touch reference count for s. Compiler skips reference counting for const arguments. Take a look at this article plz: http://www.freepascal.org/docs-html/ref/refsu63.html That's my point. You can't say "there's no impact" if you don't do the actual reference counting (by passing an interface as const). What's the assembler for TestCOM procedure (with and without const)? ---------------------------------------------------------------------- hinst · 2014-04-17 18:39 In my test I have Code: [Select]procedure TestCOM(const aCom: IUnknown); var   b: IUnknown; begin   b := aCom;  // <- this assignment So it should work as expected; produce one _AddRef call and one _Release call. ---------------------------------------------------------------------- skalogryz · 2014-04-17 19:20 ah yes... sorry, I missed that. ---------------------------------------------------------------------- BeniBela · 2014-04-17 21:57 That is kind of irrelevant. Ref counting is ref counting, ofc it has around the same speed if implemented manually and via COM object. The real issue is that with interfaces it is known which method is called during compile time, and has to be looked up during run-time. Especially since that breaks inlining ---------------------------------------------------------------------- Martin_fr · 2014-04-17 22:47 Actually, ref counting by hand, can produce faster code. If the compiler adds recounting (for local var), the compiler always assumes the procedure could be exited by exception. Therefore the compiler inserts an "try finally" too. If you add ref counting by hand, you may know that there can not be an exception, and you can skip the try finally. So you save the try finally time. ---------------------------------------------------------------------- marcov · 2014-04-18 07:22 Quote from: Martin_fr on April 18, 2014, 12:47:03 amActually, ref counting by hand, can produce faster code. If the compiler adds recounting (for local var), the compiler always assumes the procedure could be exited by exception. Therefore the compiler inserts an "try finally" too. If you add ref counting by hand, you may know that there can not be an exception, and you can skip the try finally. So you save the try finally time. Or just use {$implicitexceptions off} ---------------------------------------------------------------------- taazz · 2014-04-18 09:09 Quote from: marcov on April 18, 2014, 09:22:39 amOr just use {$implicitexceptions off} ---------------------------------------------------------------------- hinst · 2014-09-08 08:50 will we ever have reference counting for user types in FPC? ever? this is long overdue. seriously. Of all FPC flaws, this one is the most annoying. FPC has reference counting for interfaces, strings and dyn arrays, but not for user types. It just feels wrong. Like it teases me is there a way to make this work? some hack? anything? ---------------------------------------------------------------------- marcov · 2014-09-08 09:21 Quote from: hinst on September 08, 2014, 10:50:17 amwill we ever have reference counting for user types in FPC? ever? Not that I know. Quotethis is long overdue. seriously. That is purely opinion (and IMHO an ill-informed one) QuoteOf all FPC flaws, this one is the most annoying. FPC has reference counting for interfaces, strings and dyn arrays, but not for user types. This has been discussed umpteen times already, please look up all discussions that reference this and/or GC. Ref counting is hard for cases where types can nest and cause cycles. The current types don't nest ref counted entities Quoteis there a way to make this work? some hack? anything? No, it is fundamental. and not desirable in the first place. Automatic memory management needs to be designed into the language, not bolted on.  Probably if you'd try that, you'd get something like Remobjects Oxygene. ---------------------------------------------------------------------- hinst · 2014-09-08 09:34 Well it works for interface types, nested or not nested it does not matter at all; in FPC one can nest interface fields 100 levels deep, and still they all will be released appropriately when no longer in scope. Problems arise when there are circular references; but I am not asking for some sophisticated algorithm which would detect circular references, I just want reference counting enabled for class types. Unfortunately I don't have money for Oxygene What I am saying is that reference counting is already here. It is fully implemented for interfaces in FPC. I just want it enabled for class types because 99% of code is about class types, not interfaces ---------------------------------------------------------------------- BigChimp · 2014-09-08 09:50 1. You're welcome to fork. As you must have realized by now if you read all those discussions, current developers simply do not think it is worth it to go that way. You obviously disagree but you won't change people's minds. 2. IIRC, the Oxygene command line compiler is/was free. ---------------------------------------------------------------------- marcov · 2014-09-08 11:25 Quote from: hinst on September 08, 2014, 11:34:46 amWell it works for interface types, nested or not nested it does not matter at all; in FPC one can nest interface fields 100 levels deep, No. Interfaces can't have fields. You can nest interfaces in objects, but not interfaces in interfaces. And objects are not refcounted. QuoteUnfortunately I don't have money for Oxygene Keep saving. QuoteWhat I am saying is that reference counting is already here. It is fully implemented for interfaces in FPC. I just want it enabled for class types because 99% of code is about class types, not interfaces Not possible. Personally, I would go for full Boehm GC in that case. That is also uncharted territory, but at least well known.  Trouble is that it has been proposed many times, but nobody really took the time to research it. And it is free! :-) ---------------------------------------------------------------------- hinst · 2014-09-08 11:38 I don't see how is it not possible; but whatever, I think I will take your word for it because I definitely don't feel like studying FPC compiler source myself ---------------------------------------------------------------------- avra · 2014-09-09 08:56 Quote from: hinst on September 08, 2014, 11:34:46 amUnfortunately I don't have money for OxygeneYou can take a look at FPC JVM: http://wiki.freepascal.org/FPC_JVM ---------------------------------------------------------------------- BeniBela · 2014-10-01 18:56 PROGRESS!!!