Please see below ...
Joe.
-----Original Message----- From: Frank Heckenbach [SMTP:frank@g-n-u.de] Sent: Monday, February 18, 2002 8:27 AM To: gpc@gnu.de Subject: Re: gcc-3+
Markus Gerwinski wrote:
Frank Heckenbach wrote:
Though I'm not sure why the distinction between store and reference pointers is necessary. Why not make all pointers the same, and when one pointer to an object is disposed of, all the other ones are invalidated?
This is usually not, what you do... is it? If the pointer p1 is the one
used
to allocate p1^, and it is also referenced by p2..pn, you normally take
care
to use p1 again to deallocate, don't you?
I don't think so. It's not uncommon, e.g., for a function to allocate and return (copy) something in a pointer, or to pass (copy) a pointer to a procedure to clean it up and dispose it. Or to allocate a pointer in a local variable, do something with it, then put it in a global list from where it's later disposed, etc.
Or do you have any arguments why these are less common situations than what you describe?
Besides, when you really want to evaluate things, you have to describe all the hidden costs first. AFAICS, for every object you need an implicit list containing all the reference pointers, so
they
can be invalidated later.
Depends on the way how to implement it...
Now I'm interested how else you'd implement it. An alternative I could think of are double-pointers, but these are slower to dereference and cause another kind of memory leak: Each second-level pointer allocated once can never be freed if you don't know if there's somewhere a first-level pointer pointing to it. I suppose that's not what you have it mind.
To be honest, I don't quite get the idea nor the problem... What exactly
do
you mean by double-pointers?
The problem is, as Marco said, how do you find all the existing reference pointers to invalidate when disposing of one store pointer.
With double pointers I mean: When you allocate some memory, you allocate another pointer to it, and let the real pointers point to that. So if you dispose of the memory, you set the other pointer to nil (or something), and you don't have to iterate over all reference pointers. The problem then would be that you can never dispose of the other pointer if you don't keep track of all existing reference pointers, so it's not a good solution.
Or how do you implement it?
[Joe da Silva]
FWIW, I see the "store pointer" being what you are describing here as the "other pointer" (I think). It points to the real data, and the "reference pointers" just point to it (the "store pointer"). Since you are not allowed to "re-new" a "store pointer" without "disposing" first, the "reference pointers" can't become "stale". I'm not sure that affects how you keep track of the "reference pointers" though, you probably still need to point back at them as you suggest ("double pointers"), since searching for them would generally be inefficient.
Frank
-- Frank Heckenbach, frank@g-n-u.de, http://fjf.gnu.de/, 7977168E GPC To-Do list, latest features, fixed bugs: http://agnes.dida.physik.uni-essen.de/~gnu-pascal/todo.html
Hi folks,
da Silva, Joe wrote:
FWIW, I see the "store pointer" being what you are describing here as the "other pointer" (I think). It points to the real data, and the "reference pointers" just point to it (the "store pointer").
That was my idea, yes... but after re-thinking, I now found an unintentional side effect: This would cause the reference pointer to _always_ point to the data of the store pointer, even if you dispose and re-new the store; the command sequence
new ( store ); ... reference:= store; (* set reference^ to store^ *) ... dispose ( store ); (* set reference to nil *) ... new ( store ); (* set reference^ to store^ ... without a command *)
would then contain a new trap to tangle up the logic of the program. The implicit handling of a store/reference concept doing exactly what it is supposed to do (hooking the reference to the _data_, not to its store) would, as Frank said, really be more complicated, I fear.
Bye
Markus
Markus Gerwinski wrote:
Frank Heckenbach wrote:
This is usually not, what you do... is it? If the pointer p1 is the one used to allocate p1^, and it is also referenced by p2..pn, you normally take care to use p1 again to deallocate, don't you?
I don't think so. It's not uncommon, e.g., for a function to allocate and return (copy) something in a pointer, or to pass (copy) a pointer to a procedure to clean it up and dispose it. Or to allocate a pointer in a local variable, do something with it, then put it in a global list from where it's later disposed, etc.
For these purposes, you still could pass a store pointer as a parameter. (Nobody prevents you from defining "Procedure foo ( bar: store )", since you never explicitly write "bar:= baz" or something.)
I don't understand. Passing a value parameter is almost the same as an assignment. I.e., if the procedure disposes of the store pointer parameter, the also store pointer in the caller gets invalid which should not happen.
With double pointers I mean: When you allocate some memory, you allocate another pointer to it, and let the real pointers point to that. So if you dispose of the memory, you set the other pointer to nil (or something), and you don't have to iterate over all reference pointers. The problem then would be that you can never dispose of the other pointer if you don't keep track of all existing reference pointers, so it's not a good solution.
I'm not quite sure, if I understand your "other" pointer right. Do you mean something like this?
var s: store; r: reference;
... new ( s ); r:= s; (* This one implicitly creates a pointer pr *) ... (* connected to s, pointing to r *) ... dispose ( s ); (* must find pr, too, set r to nil and destroy pr *)
Is that the structure you mean?
That was my first idea. The second one (quoted here) would be:
New (s); { internally: New (s); New (s^); } Foo (s^); { internally: Foo (s^^); } r := s; { internally: r := s; } Dispose (s); { internally: Dispose (s^); s^ := nil; } Foo (r^); { now r^ = nil, so error }
But you could never Dispose (s) (internally) because then r would be dangling, so you have a kind of memory leak.
Hmm, right. Here you got me. For linked-list maintenance etc., we need the free play with pointers. (Awkward... I missed the trivial case by modeling the complex ones...)
Apparently we have rather different usages in mind. For my (and GPC/GCC's) purposes, linked lists are a basic building block, i.e., almost everything is a superset of linked lists (e.g., doubly linked lists, trees, graphs, ...).
Frank
Hi folks,
Frank Heckenbach wrote:
For these purposes, you still could pass a store pointer as a parameter. (Nobody prevents you from defining "Procedure foo ( bar: store )", since you never explicitly write "bar:= baz" or something.)
I don't understand. Passing a value parameter is almost the same as an assignment. I.e., if the procedure disposes of the store pointer parameter, the also store pointer in the caller gets invalid which should not happen.
Where did I say that?
That was my first idea. The second one (quoted here) would be:
New (s); { internally: New (s); New (s^); } Foo (s^); { internally: Foo (s^^); } r := s; { internally: r := s; } Dispose (s); { internally: Dispose (s^); s^ := nil; } Foo (r^); { now r^ = nil, so error }
But you could never Dispose (s) (internally) because then r would be dangling, so you have a kind of memory leak.
Seems like the same idea Joe and I discussed in another mail, only one level higher...
Apparently we have rather different usages in mind. For my (and GPC/GCC's) purposes, linked lists are a basic building block, i.e., almost everything is a superset of linked lists (e.g., doubly linked lists, trees, graphs, ...).
It's as basic for me, too... Figure that was the reason why I overlooked it. Linked lists were a thing I took for granted.
Bye
Markus
Markus Gerwinski wrote:
Frank Heckenbach wrote:
For these purposes, you still could pass a store pointer as a parameter. (Nobody prevents you from defining "Procedure foo ( bar: store )", since you never explicitly write "bar:= baz" or something.)
I don't understand. Passing a value parameter is almost the same as an assignment. I.e., if the procedure disposes of the store pointer parameter, the also store pointer in the caller gets invalid which should not happen.
Where did I say that?
Well, maybe you didn't say that, but I assumed the purpose was to make pointer access safe.
Frank
Hi folks,
Frank Heckenbach wrote:
I don't understand. Passing a value parameter is almost the same as an assignment. I.e., if the procedure disposes of the store pointer parameter, the also store pointer in the caller gets invalid which should not happen.
Where did I say that?
Well, maybe you didn't say that, but I assumed the purpose was to make pointer access safe.
It is, but I don't see why the possibility of passing store pointers as parameters would make pointer access unsafe. So you would have the possibility of writing something like this:
...
Procedure foo ( var sp: store pointer );
begin (* foo *) ... dispose ( sp ); ... end (* foo *);
... foo ( some_global_sp ); (* disposes of sp, thus setting all *) ... (* pointers referencing sp^ to nil. *)
What's the problem here?
Bye
Markus
Markus Gerwinski wrote:
Frank Heckenbach wrote:
I don't understand. Passing a value parameter is almost the same as an assignment. I.e., if the procedure disposes of the store pointer parameter, the also store pointer in the caller gets invalid which should not happen.
Where did I say that?
Well, maybe you didn't say that, but I assumed the purpose was to make pointer access safe.
It is, but I don't see why the possibility of passing store pointers as parameters would make pointer access unsafe. So you would have the possibility of writing something like this:
...
Procedure foo ( var sp: store pointer );
I said value parameter. So let's assume you meant:
Procedure foo ( sp: store pointer );
begin (* foo *) ... dispose ( sp ); ... end (* foo *);
... foo ( some_global_sp ); (* disposes of sp, thus setting all *) ... (* pointers referencing sp^ to nil. *)
What's the problem here?
During the execution of foo you have two store pointers of the same thing, some_global_sp and sp. If this isn't a problem, then why allow this only in this special case and not allow copying store pointers in general? IOW, what's the difference why it's ok in this case, but not in other cases?
For the implementation it means that it would not only have to keep track of all reference pointers, but also of all the store pointers. I.e., if foo disposes of sp, it would also have to set some_global_sp to nil (and possibly other instances of this store pointer in other active routines as well), therefore it must be able to find them because sp and some_global_sp are not the same variable (since we're talking about value, not var, parameters).
Frank
Has anybody tried to hammer gpc into gcc3?
Apple is planning to move to gcc3 and cease support for 2.95x. They have already dumped a huge load of patches in the Darwin CVS to make everything gcc3 friendly and have cleaned up stuff like ObjC, ObjC++, gpj, g77, etc. This will be a relief since 2.95x was a huge hack job of various parts (NeXT's cc, gcc 2.7, MPW, etc.) and hopefully this will clean out a lot of the rot. Unfortunately gpc isn't compatible with gcc3.
Mac OS X is the perfect Pascal platform:
* One of the two major APIs has Pascal interfaces, specifically Carbon. Even though the library is likely written entirely in C, all the functions are extern pascal and the strings are pascal strings.
* Project Builder, a free graphical IDE, could be modified for Pascal. Project Builder uses programs like jam (which in tern uses compilers like gcc and javac) and gdb, parsing their output so if you click on an error, it highlights the error in the source file. It also combines all the resources to make executable graphical bundles.
* Interface Builder was modified by Apple to support Carbon apps and so should also work with Pascal Carbon development. Interface Builder is a graphical app which allows developers to edit the layout of controls, views, menus, windows, menus, panels, etc. A Carbon app then only has to make simple calls to the abstract utility library. If you wish I can show some example C code.
Think of the possibilities |-)