[m-dev.] interfaces (was: hash consing)

Fergus Henderson fjh at cs.mu.OZ.AU
Fri Aug 27 01:38:17 AEST 1999

[This discussion is all moot, because as we agreed uniqueness checking
requires `pragma memo_cons' to go in the interface; I'm continuing the
discussion just to elaborate on the design principles.]

On 26-Aug-1999, Peter Schachte <schachte at cs.mu.OZ.AU> wrote:
> On Wed, Aug 25, 1999 at 05:18:30PM +1000, Fergus Henderson wrote:
> > The language design decision is that anything which affects binary
> > compatibility when intermodule optimization is switched off should
> > go in the interface section. 
> > 
> > The rationale for that decision is that people should be able to write
> > components (e.g. shared libraries, DLLs, and COM or CORBA components)
> > in Mercury, and they should be able to modify the implementation section
> > of a module without it affecting the binary interface to that component.
> Being able to build components that can be shipped with just an
> interface and without source code is a useful goal.  I support this
> wholeheartedly.
> But I still don't think you've presented a good justification for the
> decision.  It is one way to achieve the component delivery goal, but
> not the only one.  And this decision runs contrary to another goal I
> haven't seen stated anywhere but I hope we can all agree on:
>     A module's interface should contain all a client module needs to
>     know to fully use that module, and nothing it doesn't need to
>     know.

I agree that that is a desirable goal.  However, I'd probably be willing
to compromise a little on the second part (i.e. include some extra
stuff in interfaces) if this was necessary to satisfy other goals,
such as supporting component-based programming (as outlined above)
with reasonable efficiency.

> Other (I think better) ways to achieve the componentization goal
> include:
>     a)	Add a compiler switch that specifies that an object file is to
> 	be delivered as a component.  When this switch is specified,
> 	turn off optimizations that would cause intermodule
> 	predicate/function interfaces to be nonstandard.

To make this work in the presence of `pragma memo_cons' in the implementation
section, the compiler would need to generate a function for every constructor,
and every construction of a data type defined in a different component
would require cross-component function call.  That would be very expensive.
So for the case of `pragma memo_cons', I would reject that approach.

>     b)	Add extra pragmas to the language, which *would* placed in the
> 	interface section, which would allow lower-level control over
> 	interfaces.

That's exactly what we've done with `pragma memo_cons'.
So this is the same as the approach that you are arguing against.

>	For example, you might want to be able to specify
> 	which registers arguments would be passed in, and other aspect
> 	of the calling conventions.  These would, of course, be
> 	implementation and architecture specific.

Well, `pragma memo_cons' will be listed in the "implementation-dependent
extensions" section of the Mercury reference manual... but that is because
we want to keep the difficulty of implementing Mercury as small as possible,
to encourage new implementations, not because it is architecture-specific
or _necessarily_ implementation-specific.

>     c)	Have the compiler generate extra information, in addition to
> 	the interface, that the compiler must use when compiling
> 	client modules.  This extra information indicates if and how
> 	calls to predicates/functions in the module should be
> 	specially compiled.  When this extra information changes,
> 	client modules must be recompiled (though they won't need to
> 	be type, mode, or determinism checked again).  In a perfect
> 	world, this extra information would be kept in the object
> 	file, but this isn't a perfect world, so this probably raises
> 	the OPNAF problem (Oh Please, Not Another File!).

That doesn't satisfy part of my design goal for component-based programming:
programmers should be able to modify the implementation section
of a module without it affecting the binary interface to that component.

>     d)	Broaden the concept of "object file" and "linkage editing" to
> 	allow linking to generated appropriate code for every
> 	predicate/function call.  This, unfortunately, won't work for
> 	DLLs, but it's a nice model for components which will be
> 	statically linked, because it leaves a lot of scope for
> 	link-time optimization.

Not working for DLLs is a pretty significant problem.
Of course the same issue arises for Unix shared objects too.

For Java byte code (or other similar systems), you could adopt approach (a)
and then hope that the optimizing JIT compiler will inline all the constructor
functions.  However, this only works if you are using an optimizing JIT,
which will not always be the case (because optimizing JITs have their own
drawbacks), and you still pay the code size cost; for applets which are
going to be downloaded across a network, the code size cost might be a
serious problem.

That's why I didn't consider any of those approaches (a), (c), or (d)
to be satisfactory.

Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at        |     -- the last words of T. S. Garp.
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au

More information about the developers mailing list