Re: [fpc-devel] Modernising Pascal
DrDiettrich wrote: Jamie McCracken wrote: GC is very inefficient with memory and current implementations tend to cost a lot performance wise too. I don't see how GC is inefficient with memory? Reference counting and (mark/sweep) garbage collection have a different runtime behaviour: Reference counting occurs with many references to objects, whereas GC only runs when required, or when idle time is left. The problem with GC is the lifetime of (dead) objects is significantly extended under GC. This means it hogs more memory for much longer. Memory allocation is also potentially slowed as a result of more objects remaining allocated on the heap so less chance of holes appearing which can be reused (unless you use a compacting GC). GC runs in a seperate thread so will incur additional overhead from that too and you cant always predict when it runs and it can snare you at the most inappropriate times (EG if memory is in short supply the thread must become extremeley aggressive to avoid swap so you will lose performance big time in those cases and with compacting variety even more so if it does end up in swap) GC gets a lot slower with the more objects you create. It's not the creation that costs GC time, instead it's the destruction of the objects. Its potentially both. All GCs have a tradeoff between memory usage and performance. A compacting one may have faster allocation but uses more memory as a result. There is no perfect GC that both uses memory efficiently and gives good performance (when compared to manual). Mixing unmanaged with managed code cause severe performance issues (marshalling penalties calling ummanaged c functions) Interoperability with C gets increasingly difficult. Writing bindings becomes much more complicated and time consuming. IMO it's never a good idea to mix managed and unmanaged code, to suffer from the worst from two worlds at the same time :-( GC is worse here because the pointers are not static in GC so referencing an object means looking up the actual address in a lookup list (so more overhead whenever you call a method or pass an object reference). GC does not use the stack efficiently and has to use a lot of heap so its extremely inefficient. Ever see GC compact swap? I don't know what GC implementation you're referring to. When memory gets too much fragmented, every memory manager has to do a compaction, that's inevitable. But GC offers a chance to update the references to moved objects, so that no address tables are required. Other memory managers don't know about the locations of pointers to the objects, so that moving objects is not possible at all! Consequently GC allows for better use of available memory, where other methods have to stop with out of memory. IMO you should learn a bit more about memory management, your argumentation doesn't look well founded to me. There are over a dozen different GC strategies so some of my points apply to some but not others (same with a lot of the replies here) thats why this thread has become long and controversial - you simply cant make a lot of generalities without specifying which type of GC you are reffering to. jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
peter green wrote: one thing i have heared (i don't use garbage collected languages much so i've never seen this myself) is that the GC gets some CPU time and starts causing stuff to be swapped in. This slows other threads down which gives the GC more CPU and causes more stuff to be swapped in. GC is started either when the system is (almost) idle, or when no more memory is available for some request. In the first case nothing is blocked by GC, and in the second case everything is blocked by out-of-memory, until the GC has collected free memory. another effect that i have seen is when CPU usage is high a garbage collected app can suck up all the systems memory. It can get all the memory it needs for itself because it can force run its garbage collector when it runs out but no other app on the system can. When GC runs in idle time, no other apps exist that could be blocked. When GC must swap something into memory, then the system is equipped with too little RAM for the current situation; in such a state everything runs slowly, due to permanent swapping. I know that people often discuss how to reduce swapping overhead, and typically they all miss the simple solution that they should extend their RAM to prevent swapping to occur at all. some objects may use resources other than memory which are more valuable and need to be freed asap. Destructors (or finalizers) can be called to release no longer required resources, even when GC is used. When it's known or suspected that an object could be destroyed, the GC can be invoked immediately. GC for itself doesn't eliminate all resource woes, of course. In special situations it may make sense to support GC with additional code, just like with any other memory management method (see below). refcounting doesn't suffer from any of theese issues Reference counting has more critical problems, like zombie objects. GC will always find and remove all dead objects, whereas reference counting never can eliminate bidirectionally linked objects, as exist in a GUI (parent - child controls). also note that use of const parameters can eliminate a huge amount of refcounting overhead. I'm not sure about the real impact of const. And even if the use of const parameters results in a significant runtime reduction, this only indicates that much more runtime could be saved by not using reference counting at all! DoDi ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
RE: [fpc-devel] Modernising Pascal
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Behalf Of DrDiettrich Sent: 26 February 2005 03:34 To: FPC developers' list Subject: Re: [fpc-devel] Modernising Pascal Jamie McCracken wrote: GC is very inefficient with memory and current implementations tend to cost a lot performance wise too. I don't see how GC is inefficient with memory? Reference counting and (mark/sweep) garbage collection have a different runtime behaviour: Reference counting occurs with many references to objects, whereas GC only runs when required, or when idle time is left. one thing i have heared (i don't use garbage collected languages much so i've never seen this myself) is that the GC gets some CPU time and starts causing stuff to be swapped in. This slows other threads down which gives the GC more CPU and causes more stuff to be swapped in. another effect that i have seen is when CPU usage is high a garbage collected app can suck up all the systems memory. It can get all the memory it needs for itself because it can force run its garbage collector when it runs out but no other app on the system can. some objects may use resources other than memory which are more valuable and need to be freed asap. refcounting doesn't suffer from any of theese issues also note that use of const parameters can eliminate a huge amount of refcounting overhead. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On Thursday 24 February 2005 14:57, Jamie McCracken wrote: It's *much* faster than reference counting everything. Reference counting is more or less the slowest garbage collection technique there is (except if only very few objects have to garbage collected). It also can't deal with circular references. Thats why I would want ref count for Tobjects and not Tcomponents. Partial ref counting should be faster than doing GC on everything. You could do partial GC as well. No one forces yo to do GC on everything. GC gets a lot slower with the more objects you create. Reference counting too. GC is worse here because the pointers are not static in GC. Not true. There are GC's with static as well as unstatic pointers (compacting GC's move pointers, but there are not compating GC's as well). For example Bohm GC (for C) does not move pointers. And it's GC. so referencing an object means looking up the actual address in a lookup list Nonsense. It's clear you don't know how typical GC works. (so more overhead whenever you call a method or pass an object reference). Nope. GC does not use the stack efficiently Complete nonsense. GC has nothing to statck. Zero, null, nada... and has to use a lot of heap so its extremely inefficient. More of the same... It's simply not true. Besides compacting GC supported directly by the langauge allows for extremely effective use of heap -- as effective as that of stack. Ever see GC compact swap? Better go learn more: http://www.iecc.com/gclist/GC-faq.html yes but with GC everything would have to be managed Nope. See above. whilst just ref counting Tobject would not cause these problems (you cant access a tobject from C anyhow). Tobject is the only weak point in Delphi's memory management so I would say using GC to correct that would be overkill. Whatever. GC has different problems but you didn't touch any. PS. there exists real-time capable GC (i.e. good for (soft)real time applications, such thing can't be said about even most non GC memory allocation systems). rgds -- Sebastian Kaliszewski ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On Thursday 24 February 2005 13:51, Jamie McCracken wrote: IMO the best solution for (almost) all of your problems were garbage collection. GC is part of Oberon, and it would fit into .NET/DotGNU as well. GC is very inefficient with memory and current implementations tend to cost a lot performance wise too. This is simply not true. If you don't belive then check the following: 1. Look with google for Quake rewrittiend into .Net (i.e. GC stuff) -- surprise surprise -- difference is neglibile (20%), 2. Look for Ocaml -- it's a heavyly GC-ed compiled language, and it's fast. GC gets a lot slower with the more objects you create. No worse that normal memory allocation, if GC is implemented properly. Mixing unmanaged with managed code cause severe performance issues (marshalling penalties calling ummanaged c functions) Interoperability with C gets increasingly difficult. Writing bindings becomes much more complicated and time consuming. I did wrote GC in C++ itself. So it binds rather well... GC is therefore a poor choice for a high performance language IMHO. There are live examples to the contrary. If anything, then refcounting is a poor choice for such language -- it's really slow, and when multithreading avareness is needed then is terribly slow. Once I compared multithreading aware and surely well optimised boost++ refcounter with my primitive GC, the very samy app using unoptimised GC was 2 times faster. In case of FPC main advantage of GC for autotatically managed stuff would be avoiding of putting the unwinding code by the compiler (those implicit try .. finally thigs). Main disadvantage is that moment of resource freeing is indefinite, and this would break exiting code (hence it's unacceptable). rgds -- Sebastian Kaliszewski ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
El Viernes, 25 de Febrero de 2005 01:36, Sebastian Kaliszewski escribió: You could do partial GC as well. No one forces yo to do GC on everything. Free Pascal object model is very flexible. If I'm not mistaken, it's compatible with Delphi so it has the same construction mechanism so it's possible to override InstanceSize, InitInstance, NewInstance and FreeInstance. There is also a reference counting hooks for interfaces. Combining all these facilities, it's possible to create a parallel hierarchies of objects that use reference count or garbage collection. -- saludos, Nico Aragón ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Sebastian Kaliszewski wrote: On Thursday 24 February 2005 14:57, Jamie McCracken wrote: It's *much* faster than reference counting everything. Reference counting is more or less the slowest garbage collection technique there is (except if only very few objects have to garbage collected). It also can't deal with circular references. Thats why I would want ref count for Tobjects and not Tcomponents. Partial ref counting should be faster than doing GC on everything. You could do partial GC as well. No one forces yo to do GC on everything. You can but that would suck! Mixing unmanaged with managed code needs a lot of effort and the performance would be detrimental (marshalling of unmanaged objects/types). GC gets a lot slower with the more objects you create. Reference counting too. GC is worse here because the pointers are not static in GC. Not true. There are GC's with static as well as unstatic pointers (compacting GC's move pointers, but there are not compating GC's as well). For example Bohm GC (for C) does not move pointers. And it's GC. I was referring to compacting GCs - non compacting ones are impractical to use unless you have tons of free memory and all the modern ones including .Net's generational one is incremently compacting. so referencing an object means looking up the actual address in a lookup list Nonsense. It's clear you don't know how typical GC works. It does in compacting GCs (how else can you get the address of an object?) (so more overhead whenever you call a method or pass an object reference). Nope. Yes for compacting GCs GC does not use the stack efficiently Complete nonsense. GC has nothing to statck. Zero, null, nada... Exactly it has to use a managed heap which is slower! Unmanaged code can use the stack for greater speed. There is a lot of talk about GCs being almost as efficient as unmanaged code but I have never seen an implementation that comes close to that. C# and Java both have poor performance in large apps where you have lots of objects (delphi 2005 is also written in .net and it is very sluggish too). and has to use a lot of heap so its extremely inefficient. More of the same... It's simply not true. Besides compacting GC supported directly by the langauge allows for extremely effective use of heap -- as effective as that of stack. But heap is slower than stack. Ever see GC compact swap? Better go learn more: http://www.iecc.com/gclist/GC-faq.html yes but with GC everything would have to be managed Nope. See above. In practice yes as above unless you can live with all the extra inefficiency. jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Sebastian Kaliszewski wrote: On Thursday 24 February 2005 13:51, Jamie McCracken wrote: IMO the best solution for (almost) all of your problems were garbage collection. GC is part of Oberon, and it would fit into .NET/DotGNU as well. GC is very inefficient with memory and current implementations tend to cost a lot performance wise too. This is simply not true. If you don't belive then check the following: 1. Look with google for Quake rewrittiend into .Net (i.e. GC stuff) -- surprise surprise -- difference is neglibile (20%), 2. Look for Ocaml -- it's a heavyly GC-ed compiled language, and it's fast. Ocaml is a functional lanaguge. Procedural languages tend to not work as efficiently with GCs from what I have seen. GC gets a lot slower with the more objects you create. No worse that normal memory allocation, if GC is implemented properly. Show me one that works properly with procedural lanaguages (java, C#, pascal etc) otherwise it just appears hypothetical. I dont doubt some languages are more suitable for this like LISP. Mixing unmanaged with managed code cause severe performance issues (marshalling penalties calling ummanaged c functions) Interoperability with C gets increasingly difficult. Writing bindings becomes much more complicated and time consuming. I did wrote GC in C++ itself. So it binds rather well... not a compacting one then - if we use compacting then you lose pointers and Pchars ergo all the existing bindings would be useless and would need to be rewritten manually (without the aid of H2pas!) GC is therefore a poor choice for a high performance language IMHO. There are live examples to the contrary. If anything, then refcounting is a poor choice for such language -- it's really slow, and when multithreading avareness is needed then is terribly slow. Once I compared multithreading aware and surely well optimised boost++ refcounter with my primitive GC, the very samy app using unoptimised GC was 2 times faster. Okay maybe its not so clear cut but Im fairly sure that to implement things correctly we would have to GC everything and the overall overhead might cost more than a partial ref counting of some Tobjects. However if your confident you can write a modern GC that would work very efficiently with FPC then by all means be my guest - I would be very interested to see it. Im not opposed to GC ing pascal if the performance/memory usuage is reasonably good. jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
This is simply not true. If you don't belive then check the following: 1. Look with google for Quake rewrittiend into .Net (i.e. GC stuff) -- surprise surprise -- difference is neglibile (20%), Though if you study more what they compare, you'll find that their .Net version is actually running at about half-speed of the commercial version, as they only compare their .Net version against a non-.Net version of the same code running under their compiler, and surprise surprise, to do that they had to change enough of the code to register a significant perf drop. Also, Quake isn't really a GC test as the code allocates most of its data only once, and then almost never uses dynamic memory. No worse that normal memory allocation, if GC is implemented properly. Actually, that's incorrect, manual memory allocation has a constant complexity cost if done properly (each alloc/free has a constant CPU cost, whatever the amount of objects allocated or their size, just don't use old fashioned linked-lists memory managers), while theoretically- best-case-GC still isn't constant time (and practical ones are more like O(n²)), GC memory allocation and heap compaction patterns are quite cache unfriendly and will require partial or total freezes while they happen. Eric ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Florian Klaempfl wrote: Jamie McCracken wrote: I did wrote GC in C++ itself. So it binds rather well... not a compacting one then - Ref. counting isn't compacting either? Not an issue cause memory allocation is conventional when ref counting. GCs allocate memory from a managed heap which fragments heavily ergo it needs compacting to be able to recycle free memory blocks more efficiently. (most GCs achieve fast memory allocation by always allocating from fresh untouched memory so you can quickly run out of memory if they dont compact exisiting used memory). jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Jamie McCracken wrote: I did wrote GC in C++ itself. So it binds rather well... not a compacting one then - Ref. counting isn't compacting either? if we use compacting then you lose pointers and Pchars ergo all the existing bindings would be useless and would need to be rewritten manually (without the aid of H2pas!) ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
This is simply not true. If you don't belive then check the following: 1. Look with google for Quake rewrittiend into .Net (i.e. GC stuff) -- surprise surprise -- difference is neglibile (20%), cost, whatever the amount of objects allocated or their size, just don't use old fashioned linked-lists memory managers), while theoretically- best-case-GC still isn't constant time (and practical ones are more like O(n?)), GC memory allocation and heap compaction patterns are quite cache unfriendly and will require partial or total freezes while they happen. In the stories about old software that is updated or reimplemented with GC/.NET/Java there are typical several caveats: - the working set with boehm GC's is typically at least twice as large(good rule of thumb) as manual allocation. Using non GCed types, explicit GC calls at timed points and setting refs to NIL can improve this slightly, but this is tuning, not a fair comparison. - Startup time is also nearly always affected severely, even if normal program execution is bearable - Critical parts are often handoptimized by using a lot of non GCed types (like int), this is not a typical programming method for these languages, but outright expert tuning. - Older applications are often not CPU limited, but have a bottleneck somewhere else. So there is a hidden CPU performanceloss in the comparison, since the managed app _is_ CPU limited apparently. - (rare) HT/SMP usage. Same with GC faqs. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On 25 feb 2005, at 15:49, Marco van de Voort wrote: - Critical parts are often handoptimized by using a lot of non GCed types (like int), this is not a typical programming method for these languages, but outright expert tuning. Critical paths are also optimized in our compiler to not use ansistrings, because reference counting is also slow. And I was talking more specific about the Quake II benchmark that was brought. Any tweaks would already be on top of the existing ones in the code. The argument is not about whether or not we should make Pascal entirely GC'd, but about whether reference counting is better/worse than other garbage collection techniques if you have a significant amount of GC'd objects. The Quake II benchmark was used to prove that full blown (I assume Boehm) GC was not slow. Q II, as tuned app, is probably already using primitive types heavily, thus not a poster child for this benchamark ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On Friday 25 February 2005 15:18, Eric Grange wrote: No worse that normal memory allocation, if GC is implemented properly. Actually, that's incorrect, manual memory allocation has a constant complexity cost if done properly (each alloc/free has a constant CPU cost, whatever the amount of objects allocated or their size, just don't use old fashioned linked-lists memory managers), 1. This is not entirely true (the cost is at best logarithmic on the number of objects or your allocator has terrible fragmentation) 2. You have to initialise your allocated data anyway. 3. In real life often you have virtual memory system underneath and there is no guarantee whatosoever. while theoretically- best-case-GC still isn't constant time GC allocation (in case of compacting collecotr) is constant time trivially, all the cost is in compacting which is linear. (and practical ones are more like O(n²)), Huh? If anything tracing is (trivially) O(m) where m is number of pointers of memory and in all but few contrived examples mn (where n is amount of allocated memory). Then most object die young so they are traced once. When you amortise the costs you'll see that tracing is allmost constant per object. Then you can go for non tracing GC, use your nearly consttime alloc/dealloc and all the overhead is tracing (which is also nearly consttime per object) GC memory allocation and heap compaction patterns are quite cache unfriendly and will require partial or total freezes while they happen. compacting GC allocation is rather more cache friendly than non GC one. Compacting Collection is not cache friendly though. Eric rgds -- Sebastian Kaliszewski ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Marco van de Voort wrote: The argument is not about whether or not we should make Pascal entirely GC'd, but about whether reference counting is better/worse than other garbage collection techniques if you have a significant amount of GC'd objects. The Quake II benchmark was used to prove that full blown (I assume Boehm) GC was not slow. Q II, as tuned app, is probably already using primitive types heavily, thus not a poster child for this benchamark Well, for a real Boehm test the FPC compiler should be used, I guess it makes a much more use of the heap than other apps :) ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
1. This is not entirely true (the cost is at best logarithmic on the number of objects or your allocator has terrible fragmentation) Not really, you can use a memory map and achieve much lower fragmentation than classic memory managers (cf. FastMM submissions in the FastCode project in the b.p.d.basm borland ng). In practice, you're memory usage will be a lot lower than that of a GC. 2. You have to initialise your allocated data anyway. That's not a practical issue because: - initialization may be a task of the user's code, thus doesn't fall to the memory manager - you can use virtual memory facilities and have the initialization to zeroes happen automagically, no need to trash the CPU cache by explicitly filling with zeroes. 3. In real life often you have virtual memory system underneath and there is no guarantee whatosoever. The management costs of the VM system are typically negligible if you don't enter the realm of disk swapping, at which point the performance of GC schemes completely collapses during garbage collections and compactions, while a classic allocator can live perfectly happily with part of its memory swapped out. GC allocation (in case of compacting collecotr) is constant time trivially, Allocation is alway constant time whatever the allocator if you do it right, that's not a comparison point, however, GC linear allocation isn't CPU-cache friendly, meaning that if you get that memory fast, the first actions you'll do on that memory will typically be an order of magnitude slower than if you had been returned cached memory (particularly noticeable for allocations of a few hundreds of kB of temporaries, string concatenations, growing arrays, etc.). Another drawback of linear allocation is interleaving, which often reduces the cache efficiency by placing heterogeneous data together (depends on the application of course, but it can hit you rather severely on some composite data structures). all the cost is in compacting which is linear. Compacting might be linear, but it's cache unfriendly, which on a modern CPU means an order of magnitude slower memory operations, and that happens practically on the whole allocated memory. If some of it was swapped out, you can then expect hell (I've seen it happen), and as compaction is a necessity of linear allocation, you can never be 100% sure to avoid it with a linearly allocating GC. Finally garbage collection isn't a linear phase, and it's also intrinsically not cache friendly (lots of random accesses all over the allocated memory, most of which are going to be cache misses). Nowadays, cache inefficiency can result in a lot of hidden perf hits, with uncached accesses being 10 or more times slower (from CPU ratios, RAM latencies, controler/chipset latencies, that all add to the CPU's own L1/L2 latencies). 10 CPU cycles doesn't sound like much, but that's enough time for a dozen+ instructions under adequate circumstances, have it happen too often, and that's enough to make the difference between smooth and sluggish. Eric ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On Friday 25 February 2005 17:29, Eric Grange wrote: 1. This is not entirely true (the cost is at best logarithmic on the number of objects or your allocator has terrible fragmentation) Not really, you can use a memory map and achieve much lower fragmentation than classic memory managers 1. Memory map brings no quarantees of const time. 2. Same applies to GC managers. BTW GC can use the very same allocation/deallocation algorithm. (cf. FastMM submissions in the FastCode project in the b.p.d.basm borland ng). In practice, you're memory usage will be a lot lower than that of a GC. You're forgetting internal fragmentation. It typical allocator allocating block with power of 2 sizes (4, 8, 16, 32, up to page size or small multiply of page size) assuming flat size distribution you have ~33% fragmentation. 2. You have to initialise your allocated data anyway. That's not a practical issue because: - initialization may be a task of the user's code, thus doesn't fall to the memory manager But must happen anyway. - you can use virtual memory facilities and have the initialization to zeroes happen automagically, no need to trash the CPU cache by explicitly filling with zeroes. No way. It does not. At best it's delayed up to the point when memory gets used actually rather than being just allocated. But then OS has to clear the page. 3. In real life often you have virtual memory system underneath and there is no guarantee whatosoever. The management costs of the VM system are typically negligible Neglibile but not const (they're mostly linear -- as memory must be cleared before porcess might use it -- due to basic security requirements). if you don't enter the realm of disk swapping, at which point the performance of GC schemes completely collapses during garbage collections Modern generational GC's are less suspectible to such problems. and compactions, Not every GC is compacting GC. while a classic allocator can live perfectly happily with part of its memory swapped out. GC allocation (in case of compacting collecotr) is constant time trivially, Allocation is alway constant time whatever the allocator if you do it right, Nope. See above below. And even of you artificially restrict yourself to small span of small object sizes yuo have to check quite a bunch of conditions, and conditional branches are not free. It's allwayes order or two of magnitude slower than adding constant to a heap pointer. that's not a comparison point, however, GC linear allocation isn't CPU-cache friendly, meaning that if you get that memory fast, the first actions you'll do on that memory will typically be an order of magnitude slower than if you had been returned cached memory (particularly noticeable for allocations of a few hundreds of kB of temporaries, string concatenations, growing arrays, etc.). 1. ever heard of memory prefetch? You can do that explicitly, but most current CPU uarchitectures does that implicitly for simple access pattersn (and linear walki is one of the simplest). 2. sorry but if you allocate few hundred of KB or more at once it won't be cached anyway, regardless of the allocator. 3. temporaries should come from stack anyway. Another drawback of linear allocation is interleaving, which often reduces the cache efficiency by placing heterogeneous data together (depends on the application of course, but it can hit you rather severely on some composite data structures). Sorry, but this goes the opposite way. Randomly scattered allocations are worse than using large compact block. Those, who have to optimise their data for cache use know that, and allocate large memory pools and then arrange data the way they want. Cache colloring and stuff is easier to do when you do not have to deal with stuff scattered everywhere. This is one of the *advantages* of compacting allocators, that they alocate with no internal fragmentation and that after compacting frequently used parts are close together, and with just somwehat smart design of compaction algorithm things used together are also placed together. This is certainly good for cache not bad (it's obvious when you look at typical CPU cache algorithm -- this minimises the amount of cache-line conflicts). all the cost is in compacting which is linear. Compacting might be linear, but it's cache unfriendly, which on a modern CPU means an order of magnitude slower memory operations, and that happens practically on the whole allocated memory. Prefetch is your friend. Then GC might be made so that not every collection has to hit entire memory. And collection is often incremental (interleaved with user code execution). If some of it was swapped out, you can then expect hell (I've seen it happen), and as compaction is a necessity of linear allocation, you can never be 100% sure to avoid it with a linearly allocating GC. Well, I had once wait ~half a minute for
Re: [fpc-devel] Modernising Pascal
Enough guys each camp can make distinct implementation. Use this forum to discuss an interface. Let the results speak for themselves. Lets discuss test code. Lets discuss benchmark code. Instead of discussing bunch of what-ifs let's see how the implementation does. Is there some wiki[1] where we can collect mentioned ideas? Jan [1] (like www.twiki.org or http://c2.com/cgi/wiki) On Feb 25, 2005, at 13:11, Sebastian Kaliszewski wrote: On Friday 25 February 2005 17:29, Eric Grange wrote: 1. This is not entirely true (the cost is at best logarithmic on the number of objects or your allocator has terrible fragmentation) Not really, you can use a memory map and achieve much lower fragmentation than classic memory managers 1. Memory map brings no quarantees of const time. 2. Same applies to GC managers. BTW GC can use the very same allocation/deallocation algorithm. (cf. FastMM submissions in the FastCode project in the b.p.d.basm borland ng). In practice, you're memory usage will be a lot lower than that of a GC. You're forgetting internal fragmentation. It typical allocator allocating block with power of 2 sizes (4, 8, 16, 32, up to page size or small multiply of page size) assuming flat size distribution you have ~33% fragmentation. 2. You have to initialise your allocated data anyway. That's not a practical issue because: - initialization may be a task of the user's code, thus doesn't fall to the memory manager But must happen anyway. - you can use virtual memory facilities and have the initialization to zeroes happen automagically, no need to trash the CPU cache by explicitly filling with zeroes. No way. It does not. At best it's delayed up to the point when memory gets used actually rather than being just allocated. But then OS has to clear the page. 3. In real life often you have virtual memory system underneath and there is no guarantee whatosoever. The management costs of the VM system are typically negligible Neglibile but not const (they're mostly linear -- as memory must be cleared before porcess might use it -- due to basic security requirements). if you don't enter the realm of disk swapping, at which point the performance of GC schemes completely collapses during garbage collections Modern generational GC's are less suspectible to such problems. and compactions, Not every GC is compacting GC. while a classic allocator can live perfectly happily with part of its memory swapped out. GC allocation (in case of compacting collecotr) is constant time trivially, Allocation is alway constant time whatever the allocator if you do it right, Nope. See above below. And even of you artificially restrict yourself to small span of small object sizes yuo have to check quite a bunch of conditions, and conditional branches are not free. It's allwayes order or two of magnitude slower than adding constant to a heap pointer. that's not a comparison point, however, GC linear allocation isn't CPU-cache friendly, meaning that if you get that memory fast, the first actions you'll do on that memory will typically be an order of magnitude slower than if you had been returned cached memory (particularly noticeable for allocations of a few hundreds of kB of temporaries, string concatenations, growing arrays, etc.). 1. ever heard of memory prefetch? You can do that explicitly, but most current CPU uarchitectures does that implicitly for simple access pattersn (and linear walki is one of the simplest). 2. sorry but if you allocate few hundred of KB or more at once it won't be cached anyway, regardless of the allocator. 3. temporaries should come from stack anyway. Another drawback of linear allocation is interleaving, which often reduces the cache efficiency by placing heterogeneous data together (depends on the application of course, but it can hit you rather severely on some composite data structures). Sorry, but this goes the opposite way. Randomly scattered allocations are worse than using large compact block. Those, who have to optimise their data for cache use know that, and allocate large memory pools and then arrange data the way they want. Cache colloring and stuff is easier to do when you do not have to deal with stuff scattered everywhere. This is one of the *advantages* of compacting allocators, that they alocate with no internal fragmentation and that after compacting frequently used parts are close together, and with just somwehat smart design of compaction algorithm things used together are also placed together. This is certainly good for cache not bad (it's obvious when you look at typical CPU cache algorithm -- this minimises the amount of cache-line conflicts). all the cost is in compacting which is linear. Compacting might be linear, but it's cache unfriendly, which on a modern CPU means an order of magnitude slower memory operations, and that happens practically on the whole allocated memory. Prefetch is your friend. Then GC might be made so that not every
Re: [fpc-devel] Modernising Pascal
Jan Ruzicka wrote / napísal (a): Enough guys each camp can make distinct implementation. Use this forum to discuss an interface. Let the results speak for themselves. Lets discuss test code. Lets discuss benchmark code. Instead of discussing bunch of what-ifs let's see how the implementation does. Is there some wiki[1] where we can collect mentioned ideas? Jan [1] (like www.twiki.org or http://c2.com/cgi/wiki) On Feb 25, 2005, at 13:11, Sebastian Kaliszewski wrote: On Friday 25 February 2005 17:29, Eric Grange wrote: 1. This is not entirely true (the cost is at best logarithmic on the number of objects or your allocator has terrible fragmentation) Not really, you can use a memory map and achieve much lower fragmentation than classic memory managers 1. Memory map brings no quarantees of const time. 2. Same applies to GC managers. BTW GC can use the very same allocation/deallocation algorithm. (cf. FastMM submissions in the FastCode project in the b.p.d.basm borland ng). In practice, you're memory usage will be a lot lower than that of a GC. You're forgetting internal fragmentation. It typical allocator allocating block with power of 2 sizes (4, 8, 16, 32, up to page size or small multiply of page size) assuming flat size distribution you have ~33% fragmentation. 2. You have to initialise your allocated data anyway. That's not a practical issue because: - initialization may be a task of the user's code, thus doesn't fall to the memory manager But must happen anyway. - you can use virtual memory facilities and have the initialization to zeroes happen automagically, no need to trash the CPU cache by explicitly filling with zeroes. No way. It does not. At best it's delayed up to the point when memory gets used actually rather than being just allocated. But then OS has to clear the page. 3. In real life often you have virtual memory system underneath and there is no guarantee whatosoever. The management costs of the VM system are typically negligible Neglibile but not const (they're mostly linear -- as memory must be cleared before porcess might use it -- due to basic security requirements). if you don't enter the realm of disk swapping, at which point the performance of GC schemes completely collapses during garbage collections Modern generational GC's are less suspectible to such problems. and compactions, Not every GC is compacting GC. while a classic allocator can live perfectly happily with part of its memory swapped out. GC allocation (in case of compacting collecotr) is constant time trivially, Allocation is alway constant time whatever the allocator if you do it right, Nope. See above below. And even of you artificially restrict yourself to small span of small object sizes yuo have to check quite a bunch of conditions, and conditional branches are not free. It's allwayes order or two of magnitude slower than adding constant to a heap pointer. that's not a comparison point, however, GC linear allocation isn't CPU-cache friendly, meaning that if you get that memory fast, the first actions you'll do on that memory will typically be an order of magnitude slower than if you had been returned cached memory (particularly noticeable for allocations of a few hundreds of kB of temporaries, string concatenations, growing arrays, etc.). 1. ever heard of memory prefetch? You can do that explicitly, but most current CPU uarchitectures does that implicitly for simple access pattersn (and linear walki is one of the simplest). 2. sorry but if you allocate few hundred of KB or more at once it won't be cached anyway, regardless of the allocator. 3. temporaries should come from stack anyway. Another drawback of linear allocation is interleaving, which often reduces the cache efficiency by placing heterogeneous data together (depends on the application of course, but it can hit you rather severely on some composite data structures). Sorry, but this goes the opposite way. Randomly scattered allocations are worse than using large compact block. Those, who have to optimise their data for cache use know that, and allocate large memory pools and then arrange data the way they want. Cache colloring and stuff is easier to do when you do not have to deal with stuff scattered everywhere. This is one of the *advantages* of compacting allocators, that they alocate with no internal fragmentation and that after compacting frequently used parts are close together, and with just somwehat smart design of compaction algorithm things used together are also placed together. This is certainly good for cache not bad (it's obvious when you look at typical CPU cache algorithm -- this minimises the amount of cache-line conflicts). all the cost is in compacting which is linear. Compacting might be linear, but it's cache unfriendly, which on a modern CPU means an order of magnitude slower memory operations, and that happens practically on the whole allocated memory. Prefetch is your friend.
Re: [fpc-devel] Modernising Pascal
Jan Ruzicka wrote: Is there some wiki[1] where we can collect mentioned ideas? http://www.freepascal.org/wiki ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
DrDiettrich wrote: My main gripes with Delphi/pascal is its additional verbosity and somewhat tedious coding practices which seem superfluous in some cases. Now I dont mind typing a bit extra to make code cleaner and more legible but I have a few ideas which would reduce needless typing and improve clarity at the same time. IMO the best solution for (almost) all of your problems were garbage collection. GC is part of Oberon, and it would fit into .NET/DotGNU as well. GC is very inefficient with memory and current implementations tend to cost a lot performance wise too. GC gets a lot slower with the more objects you create. Mixing unmanaged with managed code cause severe performance issues (marshalling penalties calling ummanaged c functions) Interoperability with C gets increasingly difficult. Writing bindings becomes much more complicated and time consuming. GC is therefore a poor choice for a high performance language IMHO. 1. Memory management. Delphi is quite incosistent here by allowing component classes to be auto managed (via their owner) whilst non-component class have to be manually managed. In a GUI a management overhead is acceptable, in other classes IMO it's not a good idea: the management costs time and requires rigid design rules, what makes it not very convenient and safe to use. no longer be a need for having loads of try..finally statements GC ;-) It might be better to do this in an IDE and get it to add the try..finally crap. EG if I say use the @ symbol to indicate a variable should be auto created and destroyed then I could have : var st@, st2@ : tstringlist; begin st.add('some text'); st2.add('some more text'); end; which the IDE would translate behind the scenes to : var st, st2 : tstringlist; begin st := tstringlist.create; try st2 := tstringlist.create; try st .add('some text'); st2.add('some more text'); finally st2.free; end; finally st.free; end; end; I do need an IDE anyhow for container based GTK2/Gnome2/Glade apps so maybe I ought to start writing one that implements this. jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On Thu, 24 Feb 2005, Jamie McCracken wrote: It might be better to do this in an IDE and get it to add the try..finally crap. EG if I say use the @ symbol to indicate a variable should be auto created and destroyed then I could have : var st@, st2@ : tstringlist; begin st.add('some text'); st2.add('some more text'); end; which the IDE would translate behind the scenes to : var st, st2 : tstringlist; begin st := tstringlist.create; try st2 := tstringlist.create; try st .add('some text'); st2.add('some more text'); finally st2.free; end; finally st.free; end; end; I do need an IDE anyhow for container based GTK2/Gnome2/Glade apps so maybe I ought to start writing one that implements this. Why don't you see if you can get this implemented as an add-on in Lazarus ? You get the rest of the IDE for free. Michael. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On 24 feb 2005, at 13:51, Jamie McCracken wrote: IMO the best solution for (almost) all of your problems were garbage collection. GC is part of Oberon, and it would fit into .NET/DotGNU as well. GC is very inefficient with memory and current implementations tend to cost a lot performance wise too. It's *much* faster than reference counting everything. Reference counting is more or less the slowest garbage collection technique there is (except if only very few objects have to garbage collected). It also can't deal with circular references. GC gets a lot slower with the more objects you create. Reference counting too. Mixing unmanaged with managed code cause severe performance issues (marshalling penalties calling ummanaged c functions) Interoperability with C gets increasingly difficult. Writing bindings becomes much more complicated and time consuming. You get the same problem if you pass a reference counted structure to C (or any other language). Jonas ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
I do need an IDE anyhow for container based GTK2/Gnome2/Glade apps so maybe I ought to start writing one that implements this. Why don't you see if you can get this implemented as an add-on in Lazarus ? You get the rest of the IDE for free. In the short term yes (although I use delphi 5 under Wine for editing stuff - its nicer on my eyes than GTK1) but long term I would love to have a GTK2 IDE integrated with Glade3 for writing HIG compliant apps as I do all my UI stuff using Glade. jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Jonas Maebe wrote: On 24 feb 2005, at 13:51, Jamie McCracken wrote: IMO the best solution for (almost) all of your problems were garbage collection. GC is part of Oberon, and it would fit into .NET/DotGNU as well. GC is very inefficient with memory and current implementations tend to cost a lot performance wise too. It's *much* faster than reference counting everything. Reference counting is more or less the slowest garbage collection technique there is (except if only very few objects have to garbage collected). It also can't deal with circular references. Thats why I would want ref count for Tobjects and not Tcomponents. Partial ref counting should be faster than doing GC on everything. GC gets a lot slower with the more objects you create. Reference counting too. GC is worse here because the pointers are not static in GC so referencing an object means looking up the actual address in a lookup list (so more overhead whenever you call a method or pass an object reference). GC does not use the stack efficiently and has to use a lot of heap so its extremely inefficient. Ever see GC compact swap? Mixing unmanaged with managed code cause severe performance issues (marshalling penalties calling ummanaged c functions) Interoperability with C gets increasingly difficult. Writing bindings becomes much more complicated and time consuming. You get the same problem if you pass a reference counted structure to C (or any other language). yes but with GC everything would have to be managed whilst just ref counting Tobject would not cause these problems (you cant access a tobject from C anyhow). Tobject is the only weak point in Delphi's memory management so I would say using GC to correct that would be overkill. jamie. Jonas ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Marco van de Voort wrote: The best solution I can think for this is to reference count non-component classes. This should be safe for TObjects but obviously not for Tcomponent descendants (cf circular reference problem) so a protected variable could be added to TObject to specify whether to ref count it or not (with TComponent turning it off). This is impossible. 90% of the language wouldn't work anymore as it does now, and besides, it would be dog slow. Could be that it gets slower than Boehm GC even. Thats very pessimistic! Why wouldn't existing code work with this? If you call free on an object it would ignore the ref count and free it - so it wont alter how existing code works so it certainly should not break anything. You can always create a new dialect that has this if you're worried about existing code (I take it most of the existing code is using FPC mode dialect). Is'nt the overhead for reference counting negligible compared to having try..finally blocks which the programmer would have to add anyway if we didn't refcount them? (there also pointers for cases where you dont need try..finally) This will improve legibility of code too as there will no longer be a need for having loads of try..finally statements to free stuff. How do you free objects then? Those try..finally's are there actually because of the refcounting. The system frees them automatically - there no need to manually add try..finally statements. The benefit is clearer code and less chance of a memory leak. 2. For Each. Its in Delphi 2005 and every modern language implements it. Yeah, and I still wonder why. There is nothing to gain with it. one less variable to manually declare 3. Increasing the number of base types to include common stuff like lists (Tlist, TStringList). Python does this nicely and theres no reason Pascal cant. I partially agree with you that the container types of Delphi aren't the strongest point. However the solution is to make a lib with better types. Pulling it in the compiler with ref counting however is something totally else, and will make them dog slow. Keep in mind that I can walk through 5-6 million (real world) objects in just under 2 secs in Pascal/Delphi on an already old 2GHz P IV, and inspect them all. Try that in Python. I know python is dog slow and its far from perfect but it does have clearer and more compact code than pascal as a result of ref counting stuff and improving the base container types. jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Jamie McCracken wrote: Marco van de Voort wrote: The best solution I can think for this is to reference count non-component classes. This should be safe for TObjects but obviously not for Tcomponent descendants (cf circular reference problem) so a protected variable could be added to TObject to specify whether to ref count it or not (with TComponent turning it off). This is impossible. 90% of the language wouldn't work anymore as it does now, and besides, it would be dog slow. Could be that it gets slower than Boehm GC even. Thats very pessimistic! Why wouldn't existing code work with this? If you call free on an object it would ignore the ref count and free it - so it wont alter how existing code works so it certainly should not break anything. You can always create a new dialect that has this if you're worried about existing code (I take it most of the existing code is using FPC mode dialect). Is'nt the overhead for reference counting negligible compared to having try..finally blocks which the programmer would have to add anyway if we didn't refcount them? (there also pointers for cases where you dont need try..finally) Ref. counting creates an huge amount of implicit try .. finally blocks which have a heavy impact on speed. Consider function f1(myobject : tobject) : tobject; begin end; function f2(myobject : iunknown) : iunknown; begin end; var o : tobject; i : iunknown; begin f1(o); f2(i); end. lets have a look at the ouput (IUnknown is ref. counted): # [2] begin .globl P$PROGRAM_F1$TOBJECT$$TOBJECT P$PROGRAM_F1$TOBJECT$$TOBJECT: # Temps allocated between ebp+0 and ebp+0 pushl %ebp movl%esp,%ebp # Var myobject located in register # Var $result located in register movl%eax,%edx # [3] result:=myobject; movl%edx,%ecx # [4] end; movl%ecx,%eax leave ret .section .text .balign 4 .balign 4 # [7] begin .globl P$PROGRAM_F2$IUNKNOWN$$IUNKNOWN P$PROGRAM_F2$IUNKNOWN$$IUNKNOWN: # Temps allocated between ebp-48 and ebp-4 pushl %ebp movl%esp,%ebp subl$48,%esp movl%ebx,-48(%ebp) # Var myobject located in register # Var $result located at ebp-4 movl%eax,%ebx movl$0,-4(%ebp) leal-16(%ebp),%eax movl%eax,%ecx leal-40(%ebp),%eax movl%eax,%edx movl$1,%eax callFPC_PUSHEXCEPTADDR callFPC_SETJMP pushl %eax testl %eax,%eax jne .L15 # [8] result:=myobject; movl%ebx,%edx leal-4(%ebp),%eax callfpc_intf_assign .L15: callFPC_POPADDRSTACK popl%eax testl %eax,%eax je .L16 # [9] end; movl$INIT__SYSTEM_IUNKNOWN,%edx leal-4(%ebp),%eax callfpc_finalize callFPC_RERAISE .L16: movl-4(%ebp),%eax movl-48(%ebp),%ebx leave ret [...] # [16] f1(o); movl%esi,%eax callP$PROGRAM_F1$TOBJECT$$TOBJECT # [17] f2(i); leal-44(%ebp),%edx movl%edx,%eax callFPC_INTF_DECR_REF movl%ebx,%eax callP$PROGRAM_F2$IUNKNOWN$$IUNKNOWN movl%eax,-44(%ebp) leal-44(%ebp),%edx movl%edx,%eax callFPC_INTF_DECR_REF movl$0,-44(%ebp) So if you look at this, you know why classes aren't ref. counted. And there is no chance to avoid the code generated for the interface. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Marco van de Voort wrote: The best solution I can think for this is to reference count non-component classes. This should be safe for TObjects but obviously not for Tcomponent descendants (cf circular reference problem) so a protected variable could be added to TObject to specify whether to ref count it or not (with TComponent turning it off). This is impossible. 90% of the language wouldn't work anymore as it does now, and besides, it would be dog slow. Could be that it gets slower than Boehm GC even. Thats very pessimistic! No, that is reading literature. Why wouldn't existing code work with this? If you call free on an object it would ignore the ref count and free it That messes up the ref counts. Make some sample code that throws some objects to different procs and keep track of ref counts. Is'nt the overhead for reference counting negligible compared to having try..finally blocks which the programmer would have to add anyway if we didn't refcount them? (there also pointers for cases where you dont need try..finally) Which one? How do you free objects then? Those try..finally's are there actually because of the refcounting. The system frees them automatically - there no need to manually add try..finally statements. The benefit is clearer code and less chance of a memory leak. Which system? The ref counting system pretty much _is_ the try finally :) 2. For Each. Its in Delphi 2005 and every modern language implements it. Yeah, and I still wonder why. There is nothing to gain with it. one less variable to manually declare Implement something in lazarus that auto-adds the variable to the local var section. No need for language extensions. D2005 reasons for it lie in the .NET, but those don't apply to the non .NET world. (yes it works in d2005/win32 too, but it is useless there) I partially agree with you that the container types of Delphi aren't the strongest point. However the solution is to make a lib with better types. Pulling it in the compiler with ref counting however is something totally else, and will make them dog slow. Keep in mind that I can walk through 5-6 million (real world) objects in just under 2 secs in Pascal/Delphi on an already old 2GHz P IV, and inspect them all. Try that in Python. I know python is dog slow and its far from perfect but it does have clearer and more compact code than pascal as a result of ref counting stuff and improving the base container types. I do not agree. /me thinks Python looks messy. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Marco van de Voort wrote: 2. For Each. Its in Delphi 2005 and every modern language implements it. Yeah, and I still wonder why. There is nothing to gain with it. one less variable to manually declare Implement something in lazarus that auto-adds the variable to the local var section. No need for language extensions. My mistake it actually avoids initialising the loop variable rather than not declaring it: for i in myarray do myarray[i] := 0; as opposed to for i := low(myarray) to high (myarray) do myarray[i] := 0; I think the for..in is much clearer and more compact (it works for sets, arrays and other enumerated types) jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On 23 feb 2005, at 14:04, Jamie McCracken wrote: My mistake it actually avoids initialising the loop variable rather than not declaring it: for i in myarray do myarray[i] := 0; as opposed to for i := low(myarray) to high (myarray) do myarray[i] := 0; I think the for..in is much clearer and more compact (it works for sets, arrays and other enumerated types) I'm not sure whether it's that clear. In case of a set, I agree, but for an array it would seem more logical to me if i iterated over all values in the array, not over all indexes. Jonas ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
My mistake it actually avoids initialising the loop variable rather than not declaring it: for i in myarray do myarray[i] := 0; as opposed to for i := low(myarray) to high (myarray) do myarray[i] := 0; I think the for..in is much clearer and more compact (it works for sets, arrays and other enumerated types) The constructs are not that frequent, so typing is not limited. I do not agree on the clearer part also. From low to high is more clear than IN, since that says nothing about order. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
On Wed, 23 Feb 2005 13:45:51 +0100 (CET) [EMAIL PROTECTED] (Marco van de Voort) wrote: one less variable to manually declare Implement something in lazarus that auto-adds the variable to the local var section. It already exists. Example: i:=0; Place cursor on i and press Code Completion (Ctrl+Shift+C) and it will add var i: integer;. Mattias ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
RE: [fpc-devel] Modernising Pascal
(note I did not use a T in front of StringList so as to distinguish it from non-base types and also to maintain backwards compatibility with existing code that uses TStringList conventionally) jamie. Are you always drunk? ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
Jamie McCracken wrote: Hi, Just wandering if any of you are interested in modernising Pascal which is looking quite dated when compared to modern languages like Python. Oh, the language which is on fortran 77 level regarding formatting? Sorry, couldn't resist :) ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
RE: [fpc-devel] Modernising Pascal
1. Memory management. Delphi is quite incosistent here by allowing component classes to be auto managed (via their owner) whilst non-component class have to be manually managed. The best solution I can think for this is to reference count non-component classes. This should be safe for TObjects but obviously not for Tcomponent descendants (cf circular reference problem) so a protected variable could be added to TObject to specify whether to ref count it or not (with TComponent turning it off). This will improve legibility of code too as there will no longer be a need for having loads of try..finally statements to free stuff. Backwards compatibility should not be affected so if you call a free method it will free it whatever its ref count. there would be quite some performance penalty to this. Refcounting is actually quite expensive especially because of the way it adds loads of extra try-finally blocks to the asm. furthermore how do you propose to do such a thing while maintaining the capability to typecast safely back and forward between object types and integer types which so much code relys on. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel
Re: [fpc-devel] Modernising Pascal
peter green wrote: 1. Memory management. Delphi is quite incosistent here by allowing component classes to be auto managed (via their owner) whilst non-component class have to be manually managed. The best solution I can think for this is to reference count non-component classes. This should be safe for TObjects but obviously not for Tcomponent descendants (cf circular reference problem) so a protected variable could be added to TObject to specify whether to ref count it or not (with TComponent turning it off). This will improve legibility of code too as there will no longer be a need for having loads of try..finally statements to free stuff. Backwards compatibility should not be affected so if you call a free method it will free it whatever its ref count. there would be quite some performance penalty to this. Refcounting is actually quite expensive especially because of the way it adds loads of extra try-finally blocks to the asm. not much more cause you would still need try finally blocks in most cases for robust code. In other cases you can use a pointer to avoid overhead (IE in cases where you are not actually creating instances). furthermore how do you propose to do such a thing while maintaining the capability to typecast safely back and forward between object types and integer types which so much code relys on. not sure I understand the problem here. Can you give an example? jamie. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel ___ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel