At 7:25 PM +0100 1/3/03, Frank Heckenbach wrote:
Grant Jacobs wrote:
[snip]
Not in those I know. They can refer to each other, but they're not tied to each other. (Might be nitpicking, but I think that's just the question at hand.)
Maybe the word 'tied' isn't the right choice, but you do get the *gist* of what I'm trying to say... And no I didn't mean to nit-pick (sorry if I'm coming across that way), I'm trying to be understood, which seems to be near impossible as people keep imposing their models on me instead of trying to understand my model! Grrr! But as I've said elsewhere, I think I might start giving up :-|
[snip]
If a unit doesn't want something to be visible to code that imports the unit, the programmer simply doesn't place that thing in the interface section of the unit. Done.
Nope. If, say, one type from the sub-unit is needed for an interface declaration, the sub-unit must be used in the interface. This generally doesn't mean that everything from it should be re-exported.
Sigh. I'm not sure if you're getting it. Whether not or not you use inheritance or make the higher level directly import dependencies (i.e. without inheritance), this same issue is present in both cases. Its not something that distinguishes the models. The uses at the lower level in inheritance and the uses at the higher level without inheritance faces the same issue of what to import (and in the case of inheritance, what to re-export). The difference is that the opportunity to have intermediate level units present what is needed for use of their unit is lost, so that without inheritance the higher levels are forced to maintain the dependencies of lower level units. Does that help?
By the way, to do this properly AFAIK, you need two places for uses per unit.
As I've said elsewhere and an earlier code example showed, there are two locations for uses under this approach. One in the interface section and one in the implementation section. The latter imports everything and the kitchen sink to implement its stuff, with no effect on other units. The former, if done properly, only imports (and hence propagates) just those things needed to satisfy the declaration part of the interface. Those are "coincidently" just the things that any importing unit must acquire to use the interface. By having the contents of this uses exported, importing units acquire them without have to maintain the actual location, etc., of these types, etc. But to do this you need (1) uses to work "in context" with the interface/implementation sections (2) two parallel uses, one in the interface section and one in the implementation section rather than having one uses work across the interface/implementation boundary (3) ideally a means of only importing a subset of an interface so that the users can choose not to propagate the whole of the lower-level interfaces.
By way of example, think about what happens if we shift fnames to another unit. Under what you've told me (assuming I'm reading you right), all units which need fnames are now going to have to be edited and re-compiled to import the new unit that now holds fnames. By contrast under the inherited model if fnames is exported by FileOps, units importing FileOps need not be changed; the inheritance looks after the dependencies. Only units immediately "above" where fnames is exported need to be updated. Higher levels will get the type regardless via inheritance. The higher levels are still getting exactly the same items, its just they no longer need to maintain the dependencies of the lower-level units.
If this is no clearer, lets call it quits. I could add two long-winded code examples of each model then compare them and what happens as you maintain the code, but it'd take too long for right now. And its getting a long way from my original intention of just trying to figure how units work in GPC and how I might address roughly the sort of scheme I had in mind.
The importing units can choose to import all, some or none of the things offered up for import by any unit it uses, assuming there is a mechanism to selectively import items (obviously importing nothing of something you use doesn't make sense, but it *is* conceptually an option!).
This places more control in the hands of the code using units.
While this is true (and possible with GPC), it's not exactly in line with your original argumentation. You complained that you have to list several units (instead of one) in the `uses' clause,
Meaning that I have to list all the dependent units. See above.
now you suggest a way where you have to list many identifiers from each unit, i.e. an order of magnitude more.
I take your point, but (largely!) only those that are present in the interface declarations. In principle another way of doing this would be to have interfaces export not just the procedure and function identifiers but also the types found in the procedure/function declarations. Trouble is there may be the odd constant, etc. that the unit logically wants exported for higher-level use and you'd still need a mechanism to export these. So you might not be much better off.
Bear in mind that exporting a subset is just an option and in many cases it'd be fine to export everything (ie. the lower level unit's interface doesn't have too much extraneous junk.)
Also, how is this any worse than export in modules?
[snip]
The only way to make your example work under current schemes (as I understand them) is to move the inner bar outside foo; [...]
You really seem to have misunderstood his analogy. He wasn't trying to implement nested routines as units or vice versa, just saying that the behaviour is (in some regard) similar.
I probably tried to have my cake an eat it too ;-) I did get what he was after, I believe, its just I also tried to test out his example literally "just for the hell of it" in the same post. The two are probably kind-of tangled up...
[snip]
Grant