Marco van de Voort wrote 31 lines
> > type tmyopaguetype = type pointer;
> >
> > Since the interface must 100% define the interface so that it can
> > be used, which is a hard rule with Pascal and Modula2.
>
> Hmm, what if
>
> --- 8< ---
>
> interface
>
> type
> tMyOpaqueType; // Incomplete.
>
> private
>
> type
> // Complete type declaration, but privately.
> tMyOpaqueType = record ... end;
>
> --- 8< ---
>
> would be possible?
>
> The type is still declared in the interface part; yet, because it's
> in the private part of the interface, no other module can use it's
> inner structure.
No. Completely defines (most notably its size, probably also its
alignment if it applies). In practice, nearly all M2 compilers only
support pointers
Yes, but that's what it does, defining it, I mean. The "private" keyword would only mark it as "can't use, if you're not a child unit". It is still in the interface, and thus "completely defined" AFAICS.
Show quoted text 8 lines
> > This makes e.g. the operator overloading already hard, since it
> > can't be a record (even variant).
>
> Well, yes and no. As I wrote, you'd need to store that information
> in the unit file.
You can't. Sb might already be needing the interface before the
implementation is compiled.
Yes, I know that. (Ada is a lot more strict about it, where interface (spec) and implementation (body) are even in different files and you can actually compile your code without the body available.)
You may have overlooked it, but the "incomplete type" is already completed while still in the interface part. To be more clear on the subject, let me try a more complete example again:
--- 8< ---
unit
Foo;
interface
type
Bar = record; // Incomplete for now.
procedure FooBar (Arg : Bar);
private
type
Bar =
record
X : Integer;
Y : Double;
end;
implementation
...
end;
--- 8< ---
So it's still in the interface, the compiler has all the information it needs (even if only the interface is available at time of compilation), only that the inner working of the type is marked as sort of "non-public".
It's more a question of the type system, rather than trickery with the symbol tables.
Or you may view it as a special form of a forward declaration.
Show quoted text 9 lines
> > It is a bit the .NET class helper (partial classes) trick in a
> > modular setting.
>
> From what I understood, those partial classes are different. They
> don't extend functionality, they split it (or maybe, the call it
> "delegation of responsibility").
As far as I see it they add functionality to a base container. In
partial classes case a class, and in Ada's case a module.
Maybe. I'm not a .NET-expert, but then the name is understood that a class could be implemented in several different modules (I understood "functionality sets") and only upon completion of all modules/functionality, the resulting class as a whole is usable.
If that understanding is wrong, then I fail to see what "partial classes" do differently than a normal class. In the end, classes are there for extending them, that's more or less the whole point of OOP.
Both also seem to require to include the relevant "helper" module
explicitely to unlock the extension.
Well, in Ada there are no "helper" modules, so this must be wrong for at least this case. ;)
> > I don't like that either. The gain you get from your
> > old and trusted code, you loose in complexity and clarity of
> > overview in the module system
>
[...]
Show quoted text 7 lines
>
> I mean, I'm quite sure, you're not argueing for an "all source in
> one large file" approach... so instead of (shared) include files,
> child package would provide compiler checked extensibility.
I don't like the idea of modules being mutable (even if it only means
extension of the container)
The modules do *not* change in any way. You can extend them only by declaring it that way and need to put them in the "uses" clause if you want to use that "extended functionality".
It's no more "mutable" than adding "Math_Complex" as another unit to your source file as "extension" to the "Math" unit.
Actually, it only takes the modularization to another level and makes it even more flexible.
Show quoted text 5 lines
> IMO, it's much like the package system for the compiler. At least
> how it's laid out: You have FCL that consists of FCL.Base, FCL.XML,
> ...
I don't see any relation.
Well, I do. YMMV.
FCL only exists as parts of names and in
documentation. On src level there are only the packages, and they are
not spelled above (where they imply some hierarchic system), but with
dashes that aren't separators.
Yes, I tried to make an example, how such a system would look at source level. For me, I 1:1 relation between the documentation of an intended hierarchy and its appropriate source would be a good thing.
Show quoted text 7 lines
> > (an import of complexnumbers in one place might
> > suddenly react differently due to the partial module/classhelper)
>
> But that's the case already. Even the order of imports is
> semantically relevant (or well, it might be
But does exuse throwing out all restraint?
On the contrary, I'm trying to throw it in by making it possible to make some things more private than they are now.
> Or what's with that "reuse" keywords for the uses clause?
I'm no fan of that.
Glad to hear.
But at least it doesn't require scanning and
indexing all files up front. (though, admitted, neither do child
packages, I just fail to see their use)
Well, I used child packages to a great extend, so I am bound to see their use. And I missed them, because a hierarchical source layout for certain modules is sometimes very desirable, even if only in respect to possible name clashes.
They do have in common that a use case that would interest me could
swing me. And reuse seems to make some sense in breaking up large
header sets, though I'm not really convinced yet.
It saves about 5 minutes of typing work in a typical project. But this gets lost in the noise once you're trying to find out, which import fails your compile. While I'm at it, I ran into an interesting issue yesterday:
-- 8< -- random.pas --
unit
Random;
interface
implementation
end {Random}.
-- 8< --
-- 8< -- bp.pas --
unit
BP;
uses
Random;
interface
implementation
end {BP};
-- 8< --
-- 8< -- main.pas
uses
BP;
begin
WriteLn (Random (1.0));
end {Main}.
-- 8< --
|Compiling main.pas
|main.pas(5,13) Error: Identifier not found "Random"
|main.pas(5,20) Error: Illegal expression
Is this a bug in the compiler (I used fpc2.0.0)? Or is there any reason, why this should happen? The unit "Random" has not been used by the main program, so I would expect it to only find the "System.Random" identifier here, not the identifier of a unit, I haven't even put in the "uses" clause.
If I move the "uses Random" from the interface into the implementation part of unit "BP", it compiles again, so it seems to be a problem with the interface/implementation visibility.
(I assumed a child package would be autoloaded into a module that
imported the base package. Apparantly I'm wrong there)
Yes, you are. Of course this is not allowed to happen. Only explicitely declared "uses" are allowed.
Vinzent.