At 2:27 PM +0100 2/3/03, Frank Heckenbach wrote:
Grant Jacobs wrote:
You want to distinguish known and unknown identifiers in the error messages to make things clearer (?)
unknown identifier `%s'
type name expected, `%s' given
?
Yup. Such a major change, huh ;-) Being pedantic, I'd add 'unknown identifier' after the comma in the second line too:
type name expected, unknown identifier `%s' given
Perhaps I wasn't clear -- the second line is for the case where the identifier is known, but not a type name (but perhaps a variable).
Ah. You could just do variations on the one-liner... e.g.
type name expected, unknown identifier '%s' given type name expected, variable '%s' given type name expected, constant '%s' given
constant name expected, ...
variable name expected, ...
etc. Combinatorial logic :-)
Is this OK, or am I still off in the woop woops? (the sticks, that is)
Yes, that's why GPC has `export Foo = all' as an extension (but referring only to the current module's interface, not to re-exporting). With the proposed extension `export Foo = all (Bar, ...)', it would be possible to export all from the current interface and some selected items from imported modules (such as some types used, as in your example) which I'd consider more reasonable than just re-exporting everything.
I'd like to know more about this as it might let me do roughly what I wanted.
I've yet to implement it, so any details that may come up are still open.
OK.
But AFAICS, it will mean:
All declarations of the current interface are exported.
If a name from the current interface occurs within the parentheses with renaming, the renaming is applied. E.g.:
export Foo = all (Bar => Baz);
var Bar, Qux: Integer;
would export Bar as Baz and Qux as Qux.
If a name from the current interface occurs within the parentheses without renaming, this is redundant (maybe should be an error?).
A warning rather than an error since its only redundant?
- Any other name occuring within the parentheses must come from something imported in the interface, and is re-exported again. (With or without renaming.)
I think if you want to re-export selected items from imported units (say, an occasional type or constant), this would fit quite nicely. If, however, you routinely want to re-export everything, it will still be clumsy.
Hmm. Good except for that last one, which isn't so hot for what I was after (but I suppose other will debate that!). If you added the ability to name an imported unit rather than its contents in an export statement, it looks like the sort thing I was after. If people don't want to export unit interfaces (or parts thereof), they can just not do it. I assume unit names and other identifiers can't conflict...?
added an 'export all' of a sub module (which I think you were mentioning the other day), they'd pretty much be exact alternatives. (Export is still in the docs as 'not yet implemented!)
Don't you mean `exports' (which is, AFIAK, for BP compatible "libraries", not to be confused with `export' for EP modules)?
No. This sort of thing does make this kind of discussion confusing :-) I'm talking about modules in that paragraph (a la EP) and hence 'export'. Confused? ;-) (You've already answered part of this above.)
I meant your reference to the docs. `exports' is listed as not yet implemented (which is true), but where does it say that `export' is not yet implemented?
Sorry, you're right; export is listed as '(under construction)' (i.e. no docs for it). But I was trying to talk about export, not exports.
Read the *gist* of what I am writing more that my code which is just an incomplete skeleton. But this is all getting a bit long in the tooth -- ?
Sorry, I don't think I can do you this favour. I've just seen far too many cases of people making vague descriptions and incomplete examples, expecting us to second-guess what they really mean (which often turned out way off). Not your fault, sure. But I've given up on this, and prefer to reply to what's actually said.
For designing something you're right and I sympathetise. I'm really just trying to get the basic concepts across. When I started this I wasn't really trying to suggest this as something to implement - I was just confused as to how units work in GPC vs. how I vaguely remembered them working and wished there was something like it in GPC. Other people criticised what I posted and as if it were an implementation suggestion, which it has turned into... I'll see if I can swop over to "design mode" properly for you in a following post and try and explain things there. Its getting scattered across too many posts.
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.
That's possible with both EP modules and BP units.
But the effect of placing a uses into different places in BP units seems to have no difference in effect (aside from satisfying the interface declaration part); that is uses seems to 'ignore' the context of interface, implementation (or for that matter outside both). I'll address this properly in a later post.
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.
Not necessarily. Consider:
Unit1:
const Foo = 42;
Unit2:
uses Unit1;
type Bar = array [1 .. Foo] of Integer;
or:
Unit1:
type Foo = [...];
Unit2:
uses Unit1;
type Bar = record Baz: Foo end;
In both cases (and many more), a program can use Unit2 without using Unit1 (explicitly or implicitly) and have full access to Unit2's definitions.
Sure, but I don't think this addresses my argument. You're right as long as the program doesn't need to check the array's upper bound in case 1 or fool around with things of type Foo in case 2. In either case they'd have to do a 'uses Unit1'. What I was talking about is a scheme where a program can use Unit2 and "automatically" get (the portion of) Unit1's interface which is relevant to use of Unit2.
(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
I find this a strange idea -- the implementation gets all the declarations from its interface part, but shouldn't get its imports, but since you don't want to discuss this, we can only agree to disagree.
Ah, you're thinking something quite different about the interface section. I'll bear this in mind as I write my later post; it probably explains some of the confusion.
(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.
That's already possible with `import only' (note: for importing, not for automatic re-exporting).
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.
Yes, in this example there would be an advantage. We could probably argue about the importance of such cases. Generally, when you shift around definitions across units mid-way in a large project, you should be prepared to have some `uses' lines changed. --
Perhaps, but shouldn't you try minimise the impact of changes? Its part of what modularity, etc., is all about.
In this example there are probably units that do use FNameUnit directly and do not use FileOps, and those still have to be amended.
True: as I was trying to say the units on the immediately higher level are always going to have to be updated in such a case - probably regardless of the unit scheme chosen. But why impose these changes all the way up the unit hierarchy when "inheritance" (I'm still not sure if this is the right word) could take care of it.
(If there are no such units, then why separate FNameUnit and FileOps at all?
For one you can't forsee the future! :-) For another the sheer size and presence of common elements in the units might naturally suggest splitting a unit. Peter gives a nice e.g. of this.
Then you could just move the definition of FNames into FileOps where it would then seem to belong.)
Equally you could leave them in separate units, and use inheritance make it look as if the two are in the same unit (FileOps) to higher levels ;-)
See Peter's example, perhaps. He's also more concise than me :-)
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.
Perhaps nitpicking again: They do export the types, but not the type names. In my 2nd example above, the compiled interface of Unit2 would contain a description of type Foo, but not the identifier Foo. I.e., to a program using Unit2, but not Unit1, it would appear like a nameless type, as if Unit2 had said: `type Bar = record Baz: [...] end;'. Maybe that's clear to you, I'm mentioning it just in case, trying to avoid further confusion.
I got you, & thanks this is a nice point. But see my comments on your e.g.
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.
Of course, you could create an aritifical subrange type just to have the constant mentioned, but that would really be a kludge ... ;-)
Yeah, it would :-) And it'd be wordier than just importing the constant.
Sorry if you feel this way. However, AFAICS, no-one is claiming that your idea is the same as our model or something like this. Your presented your model, and we showed ours, then we discussed the relative pros and cons of them. Isn't this a valid form of discussion?
Yes, if people realised that their (early) criticism was actually directly at their own model! I think people are beginning to see that of their own accord anyway, so the point is moot now anyway.
Grant