From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from weis@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id XAA20200 for caml-red; Tue, 25 Jul 2000 23:52:25 +0200 (MET DST) Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id AAA14152 for ; Tue, 25 Jul 2000 00:08:56 +0200 (MET DST) Received: from isil.localdomain ([64.64.1.131]) by nez-perce.inria.fr (8.10.0/8.10.0) with ESMTP id e6OM8sT17467 for ; Tue, 25 Jul 2000 00:08:55 +0200 (MET DST) Received: by isil.localdomain (Postfix, from userid 1000) id BEA7D36CFE; Mon, 24 Jul 2000 18:09:17 -0400 (EDT) To: Julian Assange Cc: caml-list@inria.fr Subject: Re: automatic construction of mli files References: From: John Prevost Date: 24 Jul 2000 18:09:17 -0400 In-Reply-To: Julian Assange's message of "24 Jul 2000 15:34:22 +1000" Message-ID: <873dkz6v02.fsf@localhost.localdomain.> User-Agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Sender: weis@pauillac.inria.fr >>>>> "ja" == Julian Assange writes: ja> .mli files are highly redundant. Almost without exception all, ja> or at the vast majority of .mli information can be generated ja> from the underlying .ml implementation. We have programming ja> languages to reduce redundancy, not increase it. Keeping mli ja> and ml files in-sync is not only a waste of time, but ja> error-prone and from my survey often not performed correctly, ja> particularly where consistency is not enforced by the compiler ja> (e.g comments describing functions and types). While exactly ja> the same problem exists in a number of other ja> separate-compilation language implementations, we, as camlers, ja> should strive for something better. I disagree. .mli files are not at all redundant. For one thing, if you do not desire to use .mli files, you do not need to write them at all--the system works perfectly well if you use only .ml files. What .mli files are *for* is to restrict the type of a top-level module. Within the language we may write: module Foo = (struct type t = int let foo x = x let bar x = x + 1 let baz x = x end : sig type t val foo : int -> t val bar : t -> t val baz : t -> int end) in order to restrict the visibility of types. But using top-level modules, there's no declaration which may be wrapped in a type constraint. .mli serves exactly this purpose. Now--what if the language were changed to annotate such things in-line? I argue that it would not, in fact, become a better language. For the above, we might write: EXTERN opaque type t = int EXTERN int -> t let foo x = x EXTERN t -> t let bar x = x + 1 EXTERN t -> int let baz x = x Note that I don't actually recommend this syntax, I'm just trying to point out what information has to be provided. The first thing to note is that each top-level declaration must be annotated with the type you wish to export, if you want to export anything at all. I'm of two minds about this. On the one level, there are good arguments for doing it that way: the type constraints are near the code they go with. When I look at foo, I see that it's actually meant to turn an int into a t. On the other hand, it really breaks things up. When I see: type t val foo : int -> t val bar : t -> t val baz : t -> int it's very easy to see what basic types and operations on those types are provided by the module. If I want to change what information is revealed, it's pretty easy to do. And things get even hairier when you want to restrict things down more from more complex types. I personally think that making type constraints an aspect of the module-level language, and hence not supporting inline declarations of this sort of thing is good. If you want things to be transparent, don't use .mli files. In general, if you want to hide anything, I think you usually want to hide enough to make inline constraints more confusing than not. John.