Child modules draft feedback wanted
Richard A. O'Keefe
Wed Apr 5 07:27:00 CEST 2006
"Ulf Wiger \(AL/EAB\)" <> wrote:
Modules are also, to some extent, units of version control
(more on that later).
As indeed I have pointed out.
OTP has pretty good support for upgrading an application at
a time, and I think this might be a good trade-off in order
to allow cross-module inlining.
Semantically there should be no significant difference
between code that's inlined across modules and code
that isn't. It might be possible to accept _some_
well-defined differences e.g. as regards exceptions.
We already have this difference for code that is inlined within a
There are many modules in our systems as well as in OTP that
really are not reusable entities as such, except in a very
narrow context. Examples that come to mind are
- hipe_xxx_loader (xxx: amd64 | ppc64 | ppc | sparc | unified | x86)
- disk_log1, disk_log_server
- most modules in mnesia (except mnesia, mnesia_frag, and a few others)
If I've understood correctly, large chunks of dets and asn1 are like that.
The way to achieve structure today is to break a large module
into several first-class modules, but then having to document
which ones are to be viewed as "official" modules.
This is one of the things that the -export_to(Module, Functions)
directive I proposed, oh, must have been in 1997, was to have
If module foobar_helper exports everything to foobar and nothing to the
world in general, it's clearly not an "official" module.
I think child modules make a lot of sense in terms of trying
to bring more structure into complex systems.
> WHOOPS! You are doing cross-module inlining! You just made
> an incompatible change to the semantics of the language!
Even if the cross-module inlining step were skipped,
exporting the pseudo function record_info/2 would
mean that some helper code could be written a lot
So you have mod1 that exports (partial) record_info (that is, some
records have their information exported, but not others), and mod2
that imports this record_info. The problem is that without cross-
module inlining, that *does* let you enquire about record info at
run time, but it does *not* let you *use* any of that information
at compile time, so you've imported a record type from mod1, but you
can't actually *use* that record type in your source code.
In that case, you really might as well use abstract patterns.
I see very few disadvantages with doing this,
as the preprocessor has reserved both the name
and semantics of the record_info/2 function.
To me it certainly violates the principle of least surprise.
Here I am writing mod2, and want to use #fred from mod1. And I
am now allowed to import it from mod1, and I'm allowed to ask
about it at run time, but I'm not allowed to use it in my source
code. Is that weird or is that really REALLY confusing or what?
There is a conceptually much simpler change to the language which
would mean much bigger changes to the compiler and emulator, alas.
That is to do away with -record entirely and use something very
similar to IBM PROLOG's "items" = Joe Armstrong's "proper structs" =
my "frames" = (more or less) Psi-Terms. They have the same space
requirements as records, they are distinct from records, they are
even better than records because they are extensible, and they
would be a touch slower than records but not hugely so, without
requiring any kind of preprocessing or cross-module inlining.
(This is also a simpler change to the language than abstract patterns.)
That would still leave us with a use for some levels of structure
above and below the current module level, but it would eliminate the
main *principled* requirement for the preprocessor.
More information about the erlang-questions