According to Hans Ecke:
1.) heredity and virtuall routines for units (yes, I mean objects!) [...] So what I would like to see would be:
/////////////////////////////////////////////////
unit graph_fast(graph);
If I understand this correctly, you mean that your unit `graph_fast' shall export everything that `graph' does but override `putpixel' and `line' with new implementations.
Well, this is just overloading of procedures, nothing "virtual".
(* Something like "virtual procedures" in units would be the following: Program X uses unit A and calls a procedure `foo' in A. Unit B uses unit A too and overrides `foo'. "Virtual" means that program X - which does not use B directly - in fact calls `B.foo', not `A.foo'.
You do not really mean this, do you? { Well ... I just discovered: you *do* mean this. (See below.) } *)
The mechanism you suggest requires qualified identifiers, so procedures with the same name can coexist in different units in the same project. This is planned for gpc-2.2.
Up to then, you can get the intended effect of `Unit graph_fast ( Graph )' using the following kludge:
Unit Graph_Fast;
uses Graph;
Procedure Fast_PutPixel ( ... ); (* Implemented below *); Procedure Fast_Line ( ... ); (* Implemented below *);
Procedure Bar ( ... ); External; (* "Inherits" from `Graph' *)
...
Implementation
(* Implement `Fast_PutPixel' and `Fast_Line' *)
end.
Once qualified identifiers will exist, you can get rid of the `Fast_' name prefix.
Having said that, it might be a good idea to implement your idea "Unit foo ( bar )" as a shortcut to produce the result sketched above. *Perhaps* in gpc-2.2.
procedure putpixel(x,y:integer); begin writeln(logfile,`Putpixel with parameters `,x,`,`,y); inherited putpixel(x,y); end;
Okay, now you want `Graph' (or `Fast_Graph') use your overridden `PutPixel' instead of its own `PutPixel'. This can only be done with pointers, like Frank pointed out. This *is* virtuality.
If you want to implement that, modify `Graph' such that `PutPixel' is a procedural variable:
Var PutPixel: Procedure ( ... );
Then you must, of course, initialize it (perhaps in `InitGraph'), i.e. manually write a "constructor" for your "object". I have done this in the past (BO4), and it works in a great way.
(* Since our `Graph' unit is *not* a port from Borland Pascal but was rewritten from scratch and comes with full source (C and Pascal), it is *no problem* to modify it this way. :*)
To override the "virtual procedure" `PutPixel', your `Fast_Graph' unit needs to do nothing but to assign a new value to that `Putpixel' variable. You can do it with the current version of GPC (or with BP for that matter).
Maybe one could consider also Multi-heredity (is this a understandable word?)
It is, but the correct word is "multi-inheritance".
With units, this would be no real problem - provided that we are not talking about virtual procedures. When it comes to virtual procedures, the same problems arise for units as for objects.
Summary: The feature you are asking for does not (yet?) exist, but you can work around them relatively easily.
But: If you want to have the features of objects for your library, why don't your libraries export objects instead of "ordinary" procedures? I am currently writing a library (BO5) which does it that way: All input/output is done through objects having virtual methods, so you can easily replace `PutPixel' with a different routine - and the whole library will work with this new procedure. Borland's "Graph" (BGI) API is not the ultimate way to implement a graphics library. I suggest to write the library using objects and to provide some ordinary procedures that use the objects as an interface for compatibility.
2.) Making Libraries from units I don't know if this task allready done.
It is - for the objects. You can put them together in an `.a' file. (See the documentation of `ar' and `ranlib'.)
For the interfaces (`.gpi' files) this is not possible at the moment. Your "parent unit" mechanism would provide an easy way to "concat" `.gpi' files, so the calling program only needs to use *one* unit and gets the functionality of all of them. Not a bad idea.
Such a
Unit BO5 ( Tools, Objects, Events, Displays, whatever );
(* "BO5" is the name of my planned ultimative library; you can substitute "EFLIB" if you prefer something already existing. ;*)
Interface
Implementation
end.
would produce one large `.gpi' file such that "uses BO5" would give all the functionality of `Tools', `Objects', etc. to the program and tell the linker to link all the files `tools.o', `objects.o', etc.
(* Perhaps Borland's syntax "Library BO5" instead of "Unit BO5" would be a reasonable extension to directly produce `libbo5.a', i.e. automatically invoke `ar' and `ranlib'? *)
Greetings,
Peter
Dipl.-Phys. Peter Gerwinski, Essen, Germany, free physicist and programmer peter.gerwinski@uni-essen.de - http://home.pages.de/~peter.gerwinski/ [971005] maintainer GNU Pascal [971001] - http://home.pages.de/~gnu-pascal/ [971005]
Peter Gerwinski wrote:
[...]
Unit BO5 ( Tools, Objects, Events, Displays, whatever ); (* "BO5" is the name of my planned ultimative library; you can substitute "EFLIB" if you prefer something already existing. ;*) Interface Implementation end.
would produce one large `.gpi' file such that "uses BO5" would give all the functionality of `Tools', `Objects', etc. to the program and tell the linker to link all the files `tools.o', `objects.o', etc.
(* Perhaps Borland's syntax "Library BO5" instead of "Unit BO5" would be a reasonable extension to directly produce `libbo5.a', i.e. automatically invoke `ar' and `ranlib'? *)
I would not advise the use of "Library" for this purpose. In BP, "Library" is the reserved word used to make DLLs. We would expect the Win32 and OS/2 ports of GPC to produce DLLs (do they do so now?) - and, for compatibility, I would suggest that we kept "Library" for that purpose.
Best regards, The Chief -------- Dr. Abimbola A. Olowofoyeku (The African Chief) Email: laa12@keele.ac.uk Homepage: http://ourworld.compuserve.com/homepages/African_Chief/ Author of: Chief's Installer Pro 4.01 for Win16 and Win32: http://www.simtel.net/pub/simtelnet/win3/install/chief401.zip
Thank you for your answers. I would like to summarize the parts of my suggestion that I think are possible to implement acording to the answers.
First let me state, that the graph-unit is only an example. I took this example, because its IMHO really silly and very bad style to write a graphics unit for only one chip-videoboard-monitor-combination (further referenced only as the "card").I use for graphics the VESA-API.
Assume the BP-style-graph-unit and a self-made keyboard-unit and a mouse-unit. Now you want to do 3 things :
* put all of them into 2 units to make it possible to give them all away as ONE unit, not as a confusing bunch of files. You want to have one communication-with-the-user-unit and not much for different aspects. * rewrite putpixel and line to make them faster on _your_ card. * log all mouse activities to a file (can't think of a reason for that, just assuming)
the syntax would be :
///// EXAMPLE BEGINS ////////////////////
unit communication(graph,keyboard,mouse);
interface
...no interface because its unchanged ...new/changed procedures or variables would be declared here
implementation
var logfile:text;
procedure putpixel(x,y:integer); begin ...do some stuff end;
procedure line(..); begin ...write that line end;
procedure mouse_reset(); begin writeln(logfile,`mouse resetet at `,mouse_x,` `,mouse_y); inherited mouse_reset; end; ...the same with all mouse procedures
begin assign(logfile,`log`); rewrite(logfile); inherited begin; (*or inherited init? or inherited main? Don't know which is better*) end.
//////// EXAMPLE ENDS ////////////////////////
New syntax-elements needed : 1.) "unit foo(bar1,bar2,..);" 2.) "inherited <someprocedure>;" Advantages are, that this new syntax is IMHO very intuitive and uses existing keywords by carefully extending their meaning.
Discussion of the new syntax: ---------------------------- 1.) The "unit foo(bar);" part would be simple(?,IMHO): Its just that all interfaces are put after each other in order of appearence.
2.) The "inherited <someprocedure>;" part should be possible too. You have procedure-overloading. As far as I know from C++ this is implemented by translating names of procedures :
procedure foo(s:string) -> asmname "foostring" (the identifier in the) procedure foo(i:integer) -> asmname "foointeger" (.o-file, just example)
The .gpi-file includes a mapping asmname<->pascalname of all funtions that the compiler can put a call to "foostring" for a command like foo(`bar!bar??BAR!!`) and a call to "foointeger" for foo(10).
Assuming our example, the compiler reads the line "inherited putpixel(..);". It looks for the asmname of graph.putpixel and calls it. Communication.putpixel then gets its own asmname which has to be different from the one of graph.putpixel.
This is just my imagination. I'm not an expert of compiling, I just know how to type "gcc foo.c -o foo.exe" so don't take the above lines too serious.
Yours
Hans
I reread my mail and have seen, that I have wrote something un-understandable :
Assume the BP-style-graph-unit and a self-made keyboard-unit and a mouse-unit. Now you want to do 3 things :
- put all of them into 2 units to make it possible to give them all away as ONE unit, not as a confusing bunch of files. You want to have one communication-with-the-user-unit and not much for different aspects.
of course it must be : combine them all in 1 unit, to be able to give them all away as one unit not the above bunch...
There is the only question/problem I can see : We want to have one interface - this meens only one file communication.gpi. What with the object-files? Just leave them as (see example) graph.o,keyboard.o,mouse.o or build a librarie communication.a?
Also a problem with the librarie : What to do with generic units which will be included often - like system.o or crt.o - include them into the librarie?
Hans