Path: utzoo!attcan!uunet!mcvax!unido!infbs!tubsibr!postnews From: neitzel@tubsibr.uucp (Martin Neitzel) Newsgroups: comp.lang.modula2 Subject: Re: You're not my type! Message-ID: Date: 5 Jul 89 03:32:32 GMT References: Sender: postnews@tubsibr.uucp (News) Organization: TU Braunschweig, Informatik, Germany Lines: 131 Hi again! > MSRS002@ECNCDC.BITNET ("THE DOCTOR."), slightly reformatted: DOC> DOC> TYPE OneType = CARDINAL; AnotherType = CARDINAL; DOC> DOC> Are the types OneType and AnotherType compatible? PIM3 seems DOC> to say they are both compatible with CARDINAL, but doesn't say DOC> much about compatibility with each other. (I'm definitely not a member of the Zuerich crew, but anyway...) You are right, pim3 doesn't say if type compatibility is a "transitive property". DOC> I don't think OneType and AnotherType are compatible. Are DOC> they, or should they be? I consider them compatible. Our different views may both be legal. The basic reason for my view is probably the notational syntax for type declarations: "TYPE a = b". This suggests "type equality", and I personally like to transfer the transitivity associated with the mathematic equality to the compatibility of types. ("Types declared as equal", as the tutorial on page 65 puts it.) But, as you have said, there is no further formal backup enforcing this view, and you are entitled to think differently. So, I am not able to decide the question "Are they [compatible]?", but I can show that they well may be. The question of type equality is one of the major problems that our students here run into. This how we try to explain the "transitive model" to them. (This may be bothering to you, Tom, and a lot of others. But I figure there may be some beginners who are interested in it, and so I will pound on this a bit. It will explain how your JPI may compiler work, too, but if you know all this: Skip to the next section, the "Should they?") \begin {tutorial} Internally, Modula types are some kind of object with some associated descriptive information (say, memory requirements for one data value of this type, alignment, range of valid values, constituent types...) Initially, each basic type is represented in this way. To make them accessible to the poor programmer, they must be given names like INTEGER, CHAR, BOOLEAN... The symbol table (one or more of them) will usually be used to provide these links "name -> internal type description". The language provides mechanisms to build new anonymous types: e.g. "VAR z,x RECORD i,r: REAL END" will implicitly construct a new record type (==internal description for it). (Sometimes, new types will be created implicitly even when the user is not aware of it, e.g. VAR parameters may lead to the construction of new POINTER types.) Such types are anonymous because there is no identifier associated with them. The only way to give a (new) name to a type is the type declaration, "TYPE foo = ". First, this will either find the type referred to or create a new anonymous type. Then, the id "foo" is simply linked to it (as a new symbol entry). Some expamples: TYPE A = ARRAY [0..99] OF CHAR; (* PIM3, p.65 *) B = ARRAY [0..99] OF CHAR; C = A; Here, both the two ARRAY constructors will create a new internal type each, and the symbols A and B get linked to them, respectively. C will just be a second link to the first array. All internal work is done referring directly to the internal type descriptions. This is where A and C are "equal types" in this model, but A and B not. You can link more identifiers to the first array, by declarations like TYPE D = A; E = A; F = D; Since all id's refer to the same internal type, they are all equal (and compatible). Your example under this model: TYPE OneType = CARDINAL; AnotherType = CARDINAL; We end up with three identifiers referring to the internal cardinal type (CARDINAL being the first one). The second line could also have been "AnotherType = OneType", there wouldn't be any difference. \end {tutorial} This model shows a "conforming behaviour". As you said, it might also be conforming to provide a compiler with a non-transitive behaviour, supporting a useful, more rigid form of type strictness. There is nothing ``wrong'' with this. However, it has its drawbacks too. Remember the Frederico Heintz' STACK module on top of the LIST module? Consider the following example in the context of non-transitive type compatability: MODULE A; TYPE TA = ...; PROCEDURE DoItToA (a: TA) ... MODULE B; TYPE TB = TA ; PROCEDURE DoItToB (b: TB) BEGIN DoItToA(b); ... MODULE C; TYPE TC = TB ; PROCEDURE DoItToC (c: TC) BEGIN DoItToB(c); ... MODULE D; TYPE TD = TC ; PROCEDURE DoItToD (d: TD) BEGIN DoItToC(d); ... This would still be legal. But note that you probably aren't allowed to skip intermediate levels. That is, a call DoItToA(d) would be illegal (even if such a thing will happen finally if it gets triggered by DoItToD(d)). The consequence is: You can't "pass" low-level functionality to higher levels. You must re-implement functions at each intermediate level if you don't want to loose them. Depending on one's preferences, this can outweigh the benefits of a stronger type checking, perhaps by far. [NB1: You may modify all or some of the procedure parameters in this example to call-by-ref to yield other potentially interesting variants. Also note that PIM4 introduces changes in the requirements for the types of VAR parameters. This could get hairy, I don't *wanna* know...] [NB2: The language Ada gives you both possibilities: You can derive a compatible type as well as a "new", incompatible type from an existing type. Really nice.] Martin