Peter Gerwinski wrote:
> > BTW: Do TV programs actually rely on the zeroing out, or is this just a
> > paranoia initialization?
>
> They do.
Bad style! Well, at least then there should be a BIG warning in the BPCompat
objects.pas not to use the library with long strings or other schemata or
any initalized fields...
> > [String constants as Object IDs ...]
> >
> > I don't think so. If Delphi does it in a bad way, we don't have to duplicate
> > that. …
[View More]But it would be good if a Delphi user could actually check what Delphi
> > does.
>
> I don't think it's so bad: Strings are more flexible than Integers. I really
> like to index a `RessourceFile' (in TV) with Strings ...
As Pierre said: string comparison are less efficient than integer compares,
and generally I think *internal* things (i.e. things that must only be read
by computers, not by humans) should use integers rather than strings when
there's no real need for strings. Resource files, AFAIK, are binary files,
anyway, so what good would it be to have some strings scattered in them?
A different thing would be textual "resource" files (e.g. like Windoze .ini
files): for such things it can be useful to have a string ID (class name),
with the compiler switch we discussed, *additionally*, but I think the
primary ID should be an integer. (BTW: It might seem that string IDs are
"more unique" than integer IDs, but I think the opposite is the case: many
programmers will write some "TEdit" class (or "TWindow", "TString", ...),
but with integer IDs there are no problems if they choose a unique
programmer ID first.)
BTW: The compiler switch for the string class names could perhaps be saved
if the VMTs are generated in the main program (we discussed this for other
reasons, anyway). Then, the compiler could know if any part of the program
referred to a string ID (this information would have to be stored in the
.gpi file for units and modules), so the compiler could decide by itself
whether or not to include the string ID. The same, of course, is true for
the integer ID, so any program will contain just those ID(s) that it uses.
So both IDs could coexist peacefully... :-)
Syntax proposal:
Object(...)[StringID,NumID]
Either or both IDs can be omitted. NumID defaults to 0, StringID to the
class name (identifier). Accessible (readable) through fields ("object
constants") called "ClassName" and "ClassID".
> > If the "other program" is part of the standard library, it would be ok (just
> > adapting our library to accept integers). Otherwise perhaps declare a
> > function to convert a numeric ID to a string. This function would have to be
> > inserted into the Delphi source then, but with a dummy function declared in
> > Delphi, the code could still be used in Delphi.
>
> Anyway, I have more and more the impression that "Delphi compatibility"
> users desire does not mean that the GNU Pascal compiler must be able to
> compile Delphi's VCL, but that GNU Pascal has its own "VCL" with a 100%
> compatible API.
That's what I meant: if the format of the ID (string or integer) is only
relied upon by the library, we could do it differently in gpc. But I'm not
really convinced that Delphi handles these IDs as strings, could someone
please check it out?
> > BTW: What about the QueryInterface things? They might make "100% source
> > compatibility" with Delphi impossible, anyway, as soon as interfaces are
> > used.
>
> ??? Sorry, I don't understand.
I don't either... ;-)
I mean, I don't really understand what QueryInterface does, or how it's
used, but AFAI understood it, it's needed to access interfaces. If that's
right, interface acces in Delphi and gpc might be so different that programs
that use interfaces simply can't compile with Delphi and gpc at the same
time (without some {$IFDEF}s, of course). Any Delphi users to explain this
or show some code that uses interfaces?
> > I think I've found a third way, one that doesn't influence the pointer format
> > and doesn't blow up the objects. It does, however, waste some space in the
> > VMTs. I'm sending it to you by private mail (mainly because it's easier for
> > me to describe it in German) -- sorry to other readers of the list who are
> > interested in this discussion, but we'll post the results back to the list
> > -- whatever it will be finally...
>
> One pre-result: I like that third method, but it causes some techical
> problems as well. This task *is* a nontrivial one!
Next pre-result: We're getting on! I think we can use this way... :-)
> > But how many fields and which type??? I don't think that's a good idea.
>
> One additional field of type "pointer to base object" will allow to
> store as much additional information as desired with the object.
In which class, and pointer to which class? Sure, a pointer to TObject could
do anything, but would require type casts (which I consider bad style), or
absolute declarations (even worse).
> Some additional Boolean fields, stored in a packed array, cannot hurt.
>
> See `tree.*' in the GCC source code for an example of what I mean with
> "extensibility". The "tree nodes" used in the GCC and GPC front-end are
> in fact Objects (written in C, not in C++!), and they contain such
> extension fields at some central nodes in the object tree.
Sorry, I don't really feel like wading through 100kB of C code now, but I
guess they put in the "unused" fields because they're emulating objects --
for lack of an inheritance mechanism that allows to add fields when they're
really needed. So I don't see how this would apply to gpc OOP.
> > Actually, this is quite a general principle to get something like "separate
> > inheritance" (of different parts of an object), by splitting up the object
> > into several part-objects. There is an overhead (one additional pointer and
> > its dereferencing), OTOH one can often eliminate case discriminations by
> > clever use of virtual methods in the new part-objects.
>
> :-) Just what I proposed above: One additional pointer.
> It seems that we in fact agree, but we chose different words for it.
Not completely: my suggestion is to introduce pointers to appropriate types,
e.g. pointers to some kind of video objects from all classes that access
video. The (abstract) video class would provide the services required by
those classes. That's a bit more specific than just a general purpose
pointer.
Another thing (not belonging to the topics above, but I didn't want to start
a new mail):
I think it could be useful to let the "IS" operator do an implicit type cast,
so e.g. the following would compile:
type
a=object
end;
b=object(a)
c:integer
end;
var d:^a;
begin
if d^ is b then writeln(d^.c)
end.
So when an "if" condition contains just one "is"-comparison (no other
conditions with "and" or "or"), the object should be type cast to the
actual type for the scope of the "then" statement. (Of course, this could
be generalized to more compilcated conditions, but I think this simple case
would suffice for most purposes.)
I don't know how difficult this is to implement, but it would be a nice
feature. E.g., in a program I have some situations like:
if CurrentEditor^ is TTextEditor
then TTextEditor(CurrentEditor^).TextSearch(...)
I think this type cast should be superfluous (from a "high level" point of
view). (Of course, the "is" currently is a "TypeOf" comparison.)
--
Frank Heckenbach, Erlangen, Germany
heckenb(a)mi.uni-erlangen.de
Turbo Pascal: http://www.mi.uni-erlangen.de/~heckenb/programs.htm
Internet links: http://www.mi.uni-erlangen.de/~heckenb/links.htm
[View Less]
I have always missed (in BP) an extension to Exit in the form of
Exit(RetValue), just like C's return.
Its not important, but its something that I have always wanted :-)
________________________
| _) | | e-mail: bernie(a)icenet.com.au
|___)ernhard |_|schirren ptschirrenb(a)cc.curtin.edu.au
www: www.geocities.com/CollegePark/Quad/8070/
>If it looks weird for you, never mind, it does so for me as well. You don't
>need to worry about all this unless you want to change from UCSD-style Units
>to EP-style Modules. ;-)
It sure does look a little wierd (from a BP standpoint). But I suppose
standards are there to make life more complicating :-)
>From another email:
> Maybe we can savely drop the `.gpm' file for Units. The only thing I am
> worrying about is whether it will still be possible then to use Modules …
[View More]and
> Units in the same project. But I will check ...
Most (normal?!?) people would only use one type of unit in their projects
anyway. I agree with Frank Heckenbach, I also don't like to have many files
around.
Cheers
________________________
| _) | | e-mail: bernie(a)icenet.com.au
|___)ernhard |_|schirren ptschirrenb(a)cc.curtin.edu.au
www: www.geocities.com/CollegePark/Quad/8070/
[View Less]
Here I am again! :-) I have yet another slight problem...
The GPC procedural types do not allow VAR parameters! I looked through all
the documentation but couldn't find any way of doing it - other than using
pointers.
Im sure a feature like this was not overlooked! :-)
________________________
| _) | | e-mail: bernie(a)icenet.com.au
|___)ernhard |_|schirren ptschirrenb(a)cc.curtin.edu.au
www: www.geocities.com/CollegePark/Quad/8070/
Is it possible to specify the value of an enumerated type? I was trying to
port a C header file which did something like this:
typedef enum hello_everybody {
hello_error = -1,
hello_first = 0,
hello_second,
hello_third
...
Can this be done with GPC?
Thanks
________________________
| _) | | e-mail: bernie(a)icenet.com.au
|___)ernhard |_|schirren ptschirrenb(a)cc.curtin.edu.au
www: www.geocities.com/CollegePark/Quad/8070/
According to Orlando Llanes:
>
> Thanks for the help with the port statements! I figure that $define'ing
> them will save time because of no stack operations (right? :}).
Right. (Except the `volatile' problem Juki pointed out, GPC should
do all this automatically with `-O3', but until that day, you can
work around using the (*$define foo(bar) ... *) kludge.)
> I was looking at the FAQ again,
> and saw the license, I can see that GPC can be as
> big as GCC, but the problem …
[View More]I have is that what I want with it conflicts
> with it's license, I want to develop computer games commercial/shareware.
This does not conflict with the license at all. Myself am planning to
make a living with programs I will write with GNU Pascal. (At the moment,
I still write most of them with Borland Pascal, but I already sold one
written with GPC ... :)
> I will be writing my own Game Libraries, and am willing to make them free
> under GNU to develop commercially or for education.
Be welcome to do that! :) I suggest to put it under the LGPL, not the
ordinary GPL, because then it's easier to use it with programs you don't
want to release the source.
* It is NOT required that you publish the source of your programs when
using an LGPLed library; when using a GPLed library, this IS required
unless stated otherwise explicitly in its license.
* When using an LGPLed library, you must ensure that the client can modify
(e.g. upgrade) the library, and your program will work with the new
version. The easiest way to achieve this is to link it dynamically.
* When using a GPLed library, you still have the possibility to write a
free (GPLed) program which cooperates with your own program. Then you
can sell both. (It's OKAY to charge a fee - as much as you wish and
your clients are willing to pay - for the free program, but the clients
must be allowed to redistribute the free program.)
(While I was first shocked by the thought that I would have to release
the source of some of my programs, I meanwhile think that the idea is not
that bad: It makes it easier to fix bugs when the client has the source!)
> But what puts me in the
> spot is that the license in a way says I can't develop comemrcially?
> Are there exceptions or exclusions?
The definitions of "commercial" and "free" software don't exclude each
other. You are welcome to distribute free software, e.g. GNU Pascal
itself, for a fee. There are companies like Cygnus Solutions making
a living this way.
For details about "selling free software", see
http://www.gnu.ai.mit.edu/philosophy/selling.html
mirrored in Germany as
http://agnes.dida.physik.uni-essen.de/~gnu/philosophy/selling.html
but - once again - it is NO PROBLEM to use GNU Pascal for writing non-free
software. I only recommend to read the licenses of all libraries you are
using carefully - including the GNU Pascal run-time library. (... which
you should do anyway, regardless which compiler and libraries you are going
to use.)
Greetings,
Peter
Dipl.-Phys. Peter Gerwinski, Essen, Germany, free physicist and programmer
peter.gerwinski(a)uni-essen.de - http://home.pages.de/~peter.gerwinski/ [970201]
maintainer GNU Pascal [970510] - http://home.pages.de/~gnu-pascal/ [970125]
[View Less]
Juki wrote:
> PredatorZeta wrote:
> > Warning: return value of function not assigned
>
> Right, gpc does not handle this properly. [...]
Now it does. :-)
> > =8-||||| AAAAAAAARRRRGGGHHH!!!8-)) Whatta the lines 7 and 8 do??????
> > NOTHING!!!
> > [...]
>
> I think this is because the return value of the function
> is declared volatile to prevent optimization screwing
> it up. I remember having problems with this, so please don't
> …
[View More]remove the volatile stuff until the real problem is tracked.
> [...]
I'll see what I can do against that ...
Peter
Dipl.-Phys. Peter Gerwinski, Essen, Germany, free physicist and programmer
peter.gerwinski(a)uni-essen.de - http://home.pages.de/~peter.gerwinski/ [970201]
maintainer GNU Pascal [970510] - http://home.pages.de/~gnu-pascal/ [970125]
[View Less]
According to Frank Heckenbach:
>
> > At least a `BPcompat Objects' Unit *must* have this FillChar. :-|
>
> Hmmm... there could be problems if an object in a ported BP program has a
> string field (at least until short strings are implemented and "string[]"
> automatically generates short strings).
I hope that I will be able to implement them not too far in the future.
> BTW: Do TV programs actually rely on the zeroing out, or is this just a
> paranoia …
[View More]initialization?
They do.
> [...] Since gpc
> favours speed instead of size, I think it's good to do the initialization
> outside.
Agreed.
> But then the question is whether to initialize the VMT before the call.
> With the method below, it's simple: initialize it if (and only if) it
> hasn't been initialized before.
Exactly. This implies that pre-initialization is necessary.
> I think this is a good idea. Perhaps also resetting the VMT after a
> destructor call (which is superfluous in a Dispose statement, of course).
Yes.
> [String constants as Object IDs ...]
>
> I don't think so. If Delphi does it in a bad way, we don't have to duplicate
> that. But it would be good if a Delphi user could actually check what Delphi
> does.
I don't think it's so bad: Strings are more flexible than Integers. I really
like to index a `RessourceFile' (in TV) with Strings ...
> If the "other prorgam" is part of the standard library, it would be ok (just
> adapting our library to accept integers). Otherwise perhaps declare a
> function to convert a numeric ID to a string. This function would have to be
> inserted into the Delphi source then, but with a dummy function declared in
> Delphi, the code could still be used in Delphi.
Anyway, I have more and more the impression that "Delphi compatibility"
users desire does not mean that the GNU Pascal compiler must be able to
compile Delphi's VCL, but that GNU Pascal has its own "VCL" with a 100%
compatible API.
> BTW: What about the QueryInterface things? They might make "100% source
> compatibility" with Delphi impossible, anyway, as soon as interfaces are
> used.
??? Sorry, I don't understand.
> Doesn't the same apply to your method? You pointers are non-standard, too.
> E.g., when you want to convert them to an untyped pointer, you have to
> subtract the offset from them.
Yes. :-( A lot of work, which invites for many hard-to-decect errors.
> I think I've found a third way, one that doesn't influence the pointer format
> and doesn't blow up the objects. It does, however, waste some space in the
> VMTs. I'm sending it to you by private mail (mainly because it's easier for
> me to describe it in German) -- sorry to other readers of the list who are
> interested in this discussion, but we'll post the results back to the list
> -- whatever it will be finally...
One pre-result: I like that third method, but it causes some techical
problems as well. This task *is* a nontrivial one!
> AFAIS, this is the "aliasing bug" and can be solved with pointer-pointers.
> (See my reply to the chief, later.)
Where would that pointer-pointer reside, and who would initialize it?
When the object shows up, it must ensure that some other objects which might
not yet be in memory will be able to find the pointer to it, so they can set
up their pointer-pointers. This task works without IDs if (and only if?)
both objects are loaded at the same time.
> No, you don't disagree! :-) I said "if this doesn't work well..." --
> obviously it did after your changes! :-)
It did, and it still does. :) However, BO4 is still 16-bit technology,
supports every graphics card from CGA, Hercules, etc. to VGA (and even the
EGC card, which I saw only at two places ...), assumes DOS 2.11 and at least
one floopy disk drive (hard disk recommended, but not required), etc. It's
time for something more powerful and not restricted by Borland's copyright!
> But how many fields and which type??? I don't think that's a good idea.
One additional field of type "pointer to base object" will allow to
store as much additional information as desired with the object.
Some additional Boolean fields, stored in a packed array, cannot hurt.
See `tree.*' in the GCC source code for an example of what I mean with
"extensibility". The "tree nodes" used in the GCC and GPC front-end are
in fact Objects (written in C, not in C++!), and they contain such
extension fields at some central nodes in the object tree.
> Actually, this is quite a general principle to get something like "separate
> inheritance" (of different parts of an object), by splitting up the object
> into several part-objects. There is an overhead (one additional pointer and
> its dereferencing), OTOH one can often eliminate case discriminations by
> clever use of virtual methods in the new part-objects.
:-) Just what I proposed above: One additional pointer.
It seems that we in fact agree, but we chose different words for it.
Greetings,
Peter
[View Less]
On Thu, 29 May 1997 15:59:51 -0400 (EDT) Pierre Phaneuf <pp(a)dilu.ml.org> wrote:
[...]
>> Yes, that is correct. The handle is not not necessary in TObject - but
>> I still feel that it does no harm to have it there.
>
>What if it did?
How can it?
>What if I use a windowing system that has long integers for window handles?
Nothing stopping you from having a different name for your handle. Also,
that is one reason for having the source code. You can change …
[View More]anything
that doesn't suit you. Apart from that, in other places, I would declare the
handle as a THandle or HWnd - the meaning of which varies depending
on the platform. In Win16 it is a Word. In Win32 it is a long integer (which
is the same as an integer in GPC).
>You have a field there that's basically of *no use*.
Ok.
>> >The instance pointer is an unique ID, why have another redundant one?
>>
>> Yes, the instance pointer is a unique ID. But this assumes that you
>> know the instance pointer. This will be the case in most situations,
>> but it won't always be the case. And, like I said in another post, there
>> are things that you can do with integers that you cannot do with
>> pointers.
>
>I don't know. Why would you know more the integer ID than the instance
>pointer?
You wouldn't. And that is the crux of the matter. In CHIEFAPP define a
GetObjectCount function which returns the number of currently active
objects. I can loop through these and do any number of things with
the information - here is a trivial example;
for i := 1 to GetObjectCount do begin
p := InstanceFromSelfID ( i );
If Assigned ( p ) then begin
If p^.Name = 'CHIEFDIALOG' then { blah blah }
else If p^.Name = 'CHIEFCONTROL' then {blah blah}
else {blah blah};
end;
end;
> And what kind of things would you do with an unique integer ID?
Inter-process communication and message passing for one. Saving
and storing things for another - the objects themselves, the state of
the desktop, the whole environment in which the program is running,
etc.
Best regards, The Chief
Dr Abimbola A. Olowofoyeku (The African Chief, and the Great Elephant)
Author of: Chief's Installer Pro v3.50 for Win16 and Win32.
Homepage: http://ourworld.compuserve.com/homepages/African_Chief/
E-mail: laa12(a)cc.keele.ac.uk
[View Less]
Peter Gerwinski wrote:
> > > Okay for ordinal types, sets and pointers, not sure about Reals.
> > > Strings initialized to zero this way are BROKEN because they get
> > > a capacity of zero which makes them useless. :-( That's one reason
> > > why I would like to have `ShortString's in GPC.)
> >
> > Ok, right, so FillChar() is a BAD idea... Ok! :-)
>
> ... except if you know exactly that no implicitly initialized types
> - at the moment,…
[View More] these are File and Schema (including String) types -
> are present in the object. Since they don't belong there anyway
> (pointers to Strings are better than Strings here), `FillChar' can
> still be useful (while dangerous - which it is always).
The danger is with (possibly unknown) descendants that declare such types.
> At least a `BPcompat Objects' Unit *must* have this FillChar. :-|
Hmmm... there could be problems if an object in a ported BP program has a
string field (at least until short strings are implemented and "string[]"
automatically generates short strings).
BTW: Do TV programs actually rely on the zeroing out, or is this just a
paranoia initialization?
> It's done like this at the moment, but BP does it in another way.
> As long as I don't know why (i.e. I suspect some disadvantages of the
> method used currently which didn't show up yet), I am very careful about
> fixing it.
BP must do it within the constructor, because it allocates the memory within
the constructor (in a "New(p,Init)" construct). This reduces the question to:
why do they allocate the memory within the constructor? I suppose they do it
in order to use a common "Constructor support routine" (in objh.asm) -- some
kind of size optimization at the expense of speed. They do that in other
places, too, most prominently the range and stack checks (which are explicit
procedure calls that save a few bytes but cause a big slowdown). Since gpc
favours speed instead of size, I think it's good to do the initialization
outside.
> > But there is another problem, namely to decide whether to call the
> > constructor virtually (i.e. looking up its address via the VMT) or
> > "statically".
>
> What's the problem? It's just calling another virtual method.
Right. I had forgotten how gpc calls constructors.
But then the question is whether to initialize the VMT before the call.
With the method below, it's simple: initialize it if (and only if) it
hasn't been initialized before.
What must be prevented is that in the following code, the "Load" call would
"initialize" p's VMT link to that of TObject (assuming Load is a virtual
constructor):
p:PObject
...
Getmem(p,...);
AssignType(p^,Typeof(TFooObject));
p^.Load(Stream);
> It is possible: I would have to pre-initialize (set the VMT to zero)
> each object variable when created: global variables at startup time, local
> variables when the procedure is entered, dynamical variables when `new'ed
> (without constructor call which would make the pre-initialization
> superfluous).
I think this is a good idea. Perhaps also resetting the VMT after a
destructor call (which is superfluous in a Dispose statement, of course).
> > I could perhaps help with designing the structures and algorithms (see
> > below ;-), if desired,
> > but probably not with hacking the compiler...
>
> Why not? GPC doesn't bite! (-; If it does, this is a bug which must be
> reported! :-)
Perhaps gcc, that gpc is written in, bites...
> (* There is only one problem with hacking GPC: It's addictive ... :*)
Yes, that's the main problem since my Recursive Time-Doubler has broken. ;-)
> > > const
> > > SIID_IActiveScriptSiteWindow = '{D10F6761-83E9-11cf-8F20-00805F2CD064}';
>
> I cannot believe that. Why should they enter it as a String constant, then?
Perhaps to make it more "readable" with the separating hyphens???
> And there are braces, etc. No, I believe that this is indeed a string to be
> interpreted by some program lying around somewhere ... so we should provide a
> string, too. :-|
I don't think so. If Delphi does it in a bad way, we don't have to duplicate
that. But it would be good if a Delphi user could actually check what Delphi
does.
> > Anyway, I think at least in gpc the internal representation should be an
> > integer, not a string.
>
> Since that other program obviously wants the number as a string surrounded by
> braces, this would be no good idea with respect to compatibility.
If the "other prorgam" is part of the standard library, it would be ok (just
adapting our library to accept integers). Otherwise perhaps declare a
function to convert a numeric ID to a string. This function would have to be
inserted into the Delphi source then, but with a dummy function declared in
Delphi, the code could still be used in Delphi.
BTW: What about the QueryInterface things? They might make "100% source
compatibility" with Delphi impossible, anyway, as soon as interfaces are
used.
> I understand that this will work, but I fear the many special cases it would
> cause to implement a non-standard-format pointer: They would be allowed in
> all contexts where "ordinary" pointers are allowed, so all internal GPC
> routines handling pointers would have to be modified. :-(
Doesn't the same apply to your method? You pointers are non-standard, too.
E.g., when you want to convert them to an untyped pointer, you have to
subtract the offset from them.
> BTW, using this method, we could also implement pointers to "ordinary" objects
> thus saving the VMT field in each instance. It's kind of an "external field"
> for each object instance ...
Right, though I doubt one would usually save memory this way, because "most"
(I guess) objects have a pointer pointing to them, many objects have even
more than one pointer. And it would complicate (to the compiler) accessing
VMT fields (ObjID, object constants, class variables).
> Facing the enormous technical problems with your method I am preparing to
> implement mine. :(Yours is nice too - sorry - and very innovative. Perhaps
> you want to try yourself on it?:)
I think I've found a third way, one that doesn't influence the pointer format
and doesn't blow up the objects. It does, however, waste some space in the
VMTs. I'm sending it to you by private mail (mainly because it's easier for
me to describe it in German) -- sorry to other readers of the list who are
interested in this discussion, but we'll post the results back to the list
-- whatever it will be finally...
> > But I still can't understand why you can't simply use the pointer from the
> > beginning, i.e. when you assign IDs (like "Factor1ID := Factor1^.ID"), you
> > just do "Factor1ID := @Factor1". Then you have the pointer when you need it.
> > Is it that the whole object "Factor1" can change (be reallocated), not only
> > its contents change -- the "aliasing bug"? [...]
>
> Here is an example from praxis.
> [skipped desription]
AFAIS, this is the "aliasing bug" and can be solved with pointer-pointers.
(See my reply to the chief, later.)
> I agree this is a design fault in TV, but I doubt that it's is possible to
> design a class library which will never need changes in the innermost part ...
No, not never. But I was objecting to the idea that everyone does their own
changes in such a library just when they need them at the moment.
> > If this doesn't work well (i.e. if many diffs between text and graphics
> > version remain), this might be an indication that TV and TV/graphics are
> > simply different enough to not share the same classes. (And actually, one
> > would hardly ever use objects of both packages in the same program.) So they
> > could be simply two packages with "similar" source then...
>
> Here I disagree. I have written some programs which can run, on demand, in
> text mode as well as in graphics mode, and *all* objects are shared between
> "both packages" (which are in fact one).
No, you don't disagree! :-) I said "if this doesn't work well..." --
obviously it did after your changes! :-)
> While generalizing Turbo Vision for graphics mode (thus creating BO3), it
> was necessary to introduce new fields to `tView'. Since I didn't have the
> TV source (I didn't want to spend 600DM (~$400) for it (but finally did,
> you know ...): ), I had to derive successor objects from *each* for-real-use
> object: `tWindow', `tDialog', `tInputLine', ... it was not only bulk of work,
> but also very unclean Pascal. Once I had the TV source, I threw away BO3,
> added the necessary fields to `tView' and essentially re-wrote TV (BO4. My
> next project of this kind, BO5, will be completely independend of TV (... like
> BO2 was. I had better continued BO2 rather than trying to use TV ...)).
>
> This example (where to have fields) proves how difficult it is to design a
> class library for general use. It might be a good idea to introduce some
> initially unemployed data fields in some base objects just for future use.
> (Not in *the* base object, but somewhere higher in the hierarchy, where
> space doesn't matter so much.)
But how many fields and which type??? I don't think that's a good idea.
Since I don't know what kind of field these are, I'm not sure if the
following applies to the situation:
Put the mode-dependent fields (those that change in all the view objects
between text and graphic mode) into a separate object. There could be an
(abstract) superclass, and special subclasses for text resp. graphics mode.
The actual objects would contain a pointer of the abstract spureclass type,
and the constructors would create text or graphics mode objects as desired.
Of course, this does involve changes to TV, but such changes that "improve"
its design (here: make it more flexible), not putting things in it that
don't belong there.
Actually, this is quite a general principle to get something like "separate
inheritance" (of different parts of an object), by splitting up the object
into several part-objects. There is an overhead (one additional pointer and
its dereferencing), OTOH one can often eliminate case discriminations by
clever use of virtual methods in the new part-objects.
--
Frank Heckenbach, Erlangen, Germany
heckenb(a)mi.uni-erlangen.de
Turbo Pascal: http://www.mi.uni-erlangen.de/~heckenb/programs.htm
Internet links: http://www.mi.uni-erlangen.de/~heckenb/links.htm
[View Less]