Path: news.daimi.aau.dk!news.daimi.aau.dk!eernst From: eernst@quercus.daimi.aau.dk (Erik Ernst) Newsgroups: comp.lang.beta Subject: Re: Information hiding in Beta (was Re: BORING newsgroup! :)) Date: 16 Dec 1994 20:08:53 GMT Organization: DAIMI, Computer Science Dept. of Aarhus Univ. Lines: 206 Message-ID: References: <3ckdaq$s7c@harbinger.cc.monash.edu.au> <3cpflq$g53@belfort.daimi.aau.dk> NNTP-Posting-Host: quercus.daimi.aau.dk In-reply-to: gunnarr@surt.ifi.uio.no's message of 15 Dec 1994 22:06:09 GMT In article gunnarr@surt.ifi.uio.no (Gunnar Rønning) writes: > On 15 Dec 1994 13:17:46 GMT, olevi@daimi.aau.dk (Ole Villumsen) said: >> I claimed earlier that Beta has information hiding. Let me > Beta has no information hiding. OTOH Mjolner, the one and only > implementation, has information hiding. I think the information hiding > mechanisms in Mjolner is very kludgy. Maybe Mjolner would be better of with > another information hiding scheme. I agree - the language BETA has absolutely no other way to control visibility of program elements than the usual scope rules. There is no notion of accessibility: everything visible is accessible. But "the language BETA" is complemented by "the fragment language", and I think that these two elements are both very important aspects of what we usually think of as "BETA". The fragment language is not a specific Mjølner gadget, it's actually not even tied specifically to BETA. All you need in order to use it (apart from an implementation, of course) is a language which can be expressed in terms of a context free grammar. Now, using the fragment language, it is possible to manage visibility and thereby accessibility of just about any conceivable piece of code from just about any other point of the program. In particular, it's possible to separate interface from implementation and to hide the implementation from and expose the interface to other parts of the program. To compare this information accessibility management scheme with that of C++ (which I consider pretty similar to that of Eiffel when comparing it to BETA together with the fragment language): - in BETA, the accessing party (the user) decides whether or not to include any given fragment group. I.e. access is seized, not granted. It is detectable from the fragment structure of the program, who seized access to what. - in C++, the accessed party (i.e. the declaration itself) has explicit accessibility properties. Access is granted. - in BETA, access rights are managed with source file granularity, because a whole source file (fragment group) is visible or invisible as a whole. On the other hand, the fragment language enables just about any set of program elements to be grouped in a source file. So the cast-in-concrete aspect is the grouping of these elements, not their accessibility. - in C++, access properties can be specified with class member granularity, i.e. the finest possible granularity - from the point of view of the accessed party. The access rights are granted in a way that is tightly integrated with the type hierarchy, and deviations from this must be expressed in terms of 'friend' declarations. Access properties of a given program element can't be modified without changing (and recompiling) the declaration of this element. Important consequences of these differences are: - in BETA, you have to use tools to verify things like "nobody outside this fragment depends on the existence and/or type of this (private) attribute", and changes anywhere in the program might change this situation. - in C++, it is much more difficult for the rest of the program outside all friend classes to access a member declared to be private. In both languages, there are lots of possible "semantic" access right violations, such as having a private member in a C++ class which is of type reference-to-T for some type T, and which is initialized with some object that "someone" might access by other means (such as another reference, or pointer). I think it is in general difficult to effectively _guarantee_ the properties of a program that we would like to assume when reading a declaration like "private:". - in BETA, it is trivially possible to have a machine dependent body fragment M, implementing some machine dependent parts of a pattern P, and then to grant access to M from the machine dependant parts M' of a specialization P' of P. Still, from the interface parts of P', M and M' are not visible, so users of P' can be machine independent. - in C++, from the point of view of the accessing party, the access declarations are much less expressive and flexible. For example, you couldn't grant a part of a class P' (e.g. a few member functions, collectively known as M') access to a subset M of the private members of a base class P. (Perhaps it is possible to make a derived class a friend and then explicitly list the private member functions Derived::priv_func_1 .. Derived::priv_func_n as friends in Base. But I couldn't get g++ to accept anything like that. Anyway, that would make the source code of class Base dependent on the private member functions of the class Derived, which is surely a Bad Thing). Schematically: P contains M privately | : P' contains M' privately | P'' M is a part of the implementation of P, do. with M'/P' P' derives-from/is-a-specialization-of P P'' derives-from/is-a-specialization-of or is-a-user-of P' M' can see M P'' can't see M or M' ---------------------------------------------------------------------- Another matter is the state of implementation of the fragment language. I suppose it's because the Mjølner people wanted to use a standard linker and have genuine separate compilation---but no matter why, there are the following important problems with the current implementation: - attribute SLOTs cannot contain substance, only patterns - patterns in SLOTs must be simple (e.g. not virtual) These limitations lead to kludges like "private: @" in: ---------------------------------------------------------------------- >>>>>>>>>> Interface.bet <<<<<<<<<< ... BODY 'Implementation'; ... SomeThing: (# ... private: @<>; ... enter arg <> #); >>>>>>>>>> Implementation.bet <<<<<<<<<< ORIGIN 'Interface'; --- SomeThingPrivate:descriptor --- (# ... anObject: @(# ... anOperation: ... #); #); --- SomeThing:dopart --- do arg->private.anObject.anOperation; ... ---------------------------------------------------------------------- A full implementation of the fragment language would allow: ---------------------------------------------------------------------- >>>>>>>>>> Interface.bet <<<<<<<<<< ... BODY 'Implementation'; ... SomeThing: (# <> ... enter arg <> #); >>>>>>>>>> Implementation.bet <<<<<<<<<< ORIGIN 'Interface'; --- SomeThingPrivate:attributes --- anObject: @(# ... anOperation: ... #); --- SomeThing:dopart --- do arg->anItem.anOperation; ... ---------------------------------------------------------------------- I don't know whether it would be possible to obtain such an implementation without loosing (genuine) seperate compilation, or paying a speed penalty for not knowing statically at the place of declaration of a pattern how big the instances of this pattern will be. It would be nice to have another almost orthogonal language (just like BETA and the fragment language are almost orthogonal, dealing with largely independent aspects of a program) for expressing properties like "non-accessedness", "constantness", "not-NONE-ness", "independence" and "dependance" of program elements. The last category, e.g., could be used to alert a programmer with dialog boxes like: "You have changed the source code of pattern P. I, programmer X, warn you that the semantics of pattern Q in file F.bet depends subtly on the implementation of pattern P, so please check it now!". sorry for rambling on like this, but I think it is a quite interesting topic :-> -- Erik Ernst eernst@daimi.aau.dk Computer Science Department of Aarhus University, Denmark